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.
Files changed (229) hide show
  1. myokit/__init__.py +9 -36
  2. myokit/__main__.py +76 -142
  3. myokit/_aux.py +62 -16
  4. myokit/_bin/example.mmt +1 -2
  5. myokit/_bin/install-win/menu.json +7 -7
  6. myokit/_config.py +22 -31
  7. myokit/_datablock.py +30 -74
  8. myokit/_datalog.py +49 -72
  9. myokit/_err.py +25 -24
  10. myokit/_expressions.py +50 -68
  11. myokit/_io.py +15 -27
  12. myokit/_model_api.py +453 -249
  13. myokit/_myokit_version.py +1 -5
  14. myokit/_parsing.py +38 -44
  15. myokit/_progress.py +5 -8
  16. myokit/_protocol.py +99 -9
  17. myokit/_sim/__init__.py +7 -24
  18. myokit/_sim/cable.c +6 -8
  19. myokit/_sim/cable.py +6 -8
  20. myokit/_sim/cmodel.h +125 -70
  21. myokit/_sim/cmodel.py +12 -14
  22. myokit/_sim/compiler.py +1 -4
  23. myokit/_sim/cvodessim.c +196 -118
  24. myokit/_sim/cvodessim.py +130 -103
  25. myokit/_sim/differential.hpp +4 -4
  26. myokit/_sim/fiber_tissue.c +4 -8
  27. myokit/_sim/fiber_tissue.py +11 -13
  28. myokit/_sim/jacobian.cpp +2 -2
  29. myokit/_sim/jacobian.py +11 -8
  30. myokit/_sim/mcl.h +53 -55
  31. myokit/_sim/opencl.py +21 -27
  32. myokit/_sim/openclsim.c +3 -7
  33. myokit/_sim/openclsim.cl +3 -3
  34. myokit/_sim/openclsim.py +49 -40
  35. myokit/_sim/pacing.h +36 -16
  36. myokit/_sim/rhs.c +6 -13
  37. myokit/_sim/rhs.py +5 -14
  38. myokit/_sim/sundials.py +1 -4
  39. myokit/_system.py +10 -16
  40. myokit/_unit.py +4 -13
  41. myokit/float.py +0 -3
  42. myokit/formats/__init__.py +8 -10
  43. myokit/formats/ansic/__init__.py +0 -3
  44. myokit/formats/ansic/_ewriter.py +2 -4
  45. myokit/formats/ansic/_exporter.py +1 -4
  46. myokit/formats/ansic/template/cable.c +4 -4
  47. myokit/formats/ansic/template/euler.c +5 -5
  48. myokit/formats/ansic/template/sim.c +6 -6
  49. myokit/formats/axon/__init__.py +1 -3
  50. myokit/formats/axon/_abf.py +12 -17
  51. myokit/formats/axon/_atf.py +5 -6
  52. myokit/formats/axon/_importer.py +0 -3
  53. myokit/formats/cellml/__init__.py +0 -3
  54. myokit/formats/cellml/_ewriter.py +3 -6
  55. myokit/formats/cellml/_exporter.py +3 -6
  56. myokit/formats/cellml/_importer.py +1 -4
  57. myokit/formats/cellml/v1/__init__.py +0 -4
  58. myokit/formats/cellml/v1/_api.py +8 -11
  59. myokit/formats/cellml/v1/_parser.py +2 -5
  60. myokit/formats/cellml/v1/_writer.py +2 -11
  61. myokit/formats/cellml/v2/__init__.py +0 -3
  62. myokit/formats/cellml/v2/_api.py +8 -17
  63. myokit/formats/cellml/v2/_parser.py +2 -5
  64. myokit/formats/cellml/v2/_writer.py +1 -4
  65. myokit/formats/channelml/__init__.py +0 -3
  66. myokit/formats/channelml/_importer.py +11 -21
  67. myokit/formats/cpp/__init__.py +1 -3
  68. myokit/formats/cpp/_ewriter.py +0 -3
  69. myokit/formats/cuda/__init__.py +0 -3
  70. myokit/formats/cuda/_ewriter.py +2 -4
  71. myokit/formats/cuda/_exporter.py +0 -3
  72. myokit/formats/cuda/template/kernel.cu +8 -5
  73. myokit/formats/easyml/__init__.py +0 -3
  74. myokit/formats/easyml/_ewriter.py +9 -11
  75. myokit/formats/easyml/_exporter.py +2 -5
  76. myokit/formats/html/__init__.py +0 -3
  77. myokit/formats/html/_exporter.py +0 -3
  78. myokit/formats/html/_flatten.py +5 -21
  79. myokit/formats/latex/__init__.py +0 -3
  80. myokit/formats/latex/_ewriter.py +1 -4
  81. myokit/formats/latex/_exporter.py +4 -6
  82. myokit/formats/mathml/__init__.py +0 -3
  83. myokit/formats/mathml/_ewriter.py +2 -11
  84. myokit/formats/mathml/_parser.py +4 -6
  85. myokit/formats/matlab/__init__.py +0 -3
  86. myokit/formats/matlab/_ewriter.py +1 -4
  87. myokit/formats/matlab/_exporter.py +2 -5
  88. myokit/formats/matlab/template/main.m +3 -2
  89. myokit/formats/opencl/__init__.py +0 -3
  90. myokit/formats/opencl/_ewriter.py +2 -4
  91. myokit/formats/opencl/_exporter.py +2 -5
  92. myokit/formats/opencl/template/cable.c +10 -10
  93. myokit/formats/opencl/template/kernel.cl +1 -1
  94. myokit/formats/opencl/template/minilog.py +1 -1
  95. myokit/formats/python/__init__.py +0 -3
  96. myokit/formats/python/_ewriter.py +2 -5
  97. myokit/formats/python/_exporter.py +0 -3
  98. myokit/formats/python/template/sim.py +14 -14
  99. myokit/formats/sbml/__init__.py +0 -3
  100. myokit/formats/sbml/_api.py +50 -44
  101. myokit/formats/sbml/_importer.py +1 -4
  102. myokit/formats/sbml/_parser.py +2 -5
  103. myokit/formats/stan/__init__.py +0 -3
  104. myokit/formats/stan/_ewriter.py +2 -4
  105. myokit/formats/stan/_exporter.py +2 -5
  106. myokit/formats/stan/template/cell.stan +3 -3
  107. myokit/formats/sympy/__init__.py +0 -3
  108. myokit/formats/sympy/_ereader.py +1 -4
  109. myokit/formats/sympy/_ewriter.py +2 -5
  110. myokit/formats/wcp/__init__.py +0 -3
  111. myokit/formats/wcp/_wcp.py +2 -8
  112. myokit/formats/xml/__init__.py +0 -3
  113. myokit/formats/xml/_exporter.py +0 -3
  114. myokit/formats/xml/_split.py +0 -3
  115. myokit/gui/__init__.py +80 -246
  116. myokit/gui/datablock_viewer.py +103 -86
  117. myokit/gui/datalog_viewer.py +214 -66
  118. myokit/gui/explorer.py +15 -21
  119. myokit/gui/ide.py +171 -144
  120. myokit/gui/progress.py +9 -9
  121. myokit/gui/source.py +406 -375
  122. myokit/gui/vargrapher.py +2 -12
  123. myokit/lib/deps.py +12 -13
  124. myokit/lib/guess.py +3 -4
  125. myokit/lib/hh.py +20 -18
  126. myokit/lib/markov.py +21 -20
  127. myokit/lib/multi.py +1 -3
  128. myokit/lib/plots.py +20 -9
  129. myokit/pacing.py +0 -3
  130. myokit/pype.py +7 -18
  131. myokit/tests/__init__.py +3 -6
  132. myokit/tests/ansic_event_based_pacing.py +1 -4
  133. myokit/tests/ansic_fixed_form_pacing.py +3 -6
  134. myokit/tests/data/beeler-1977-model-compare-b.mmt +2 -2
  135. myokit/tests/data/clancy-1999-fitting.mmt +1 -0
  136. myokit/tests/test_aux.py +13 -28
  137. myokit/tests/test_cellml_v1_api.py +4 -19
  138. myokit/tests/test_cellml_v1_parser.py +0 -15
  139. myokit/tests/test_cellml_v1_writer.py +0 -9
  140. myokit/tests/test_cellml_v2_api.py +4 -19
  141. myokit/tests/test_cellml_v2_parser.py +0 -15
  142. myokit/tests/test_cellml_v2_writer.py +0 -9
  143. myokit/tests/test_cmodel.py +16 -22
  144. myokit/tests/test_compiler_detection.py +1 -11
  145. myokit/tests/test_component.py +108 -56
  146. myokit/tests/test_config.py +34 -67
  147. myokit/tests/test_datablock.py +1 -9
  148. myokit/tests/test_datalog.py +19 -24
  149. myokit/tests/test_dependency_checking.py +8 -23
  150. myokit/tests/test_expressions.py +0 -9
  151. myokit/tests/test_float.py +1 -5
  152. myokit/tests/test_formats.py +0 -9
  153. myokit/tests/test_formats_axon.py +1 -9
  154. myokit/tests/test_formats_cellml.py +0 -15
  155. myokit/tests/test_formats_channelml.py +0 -15
  156. myokit/tests/test_formats_easyml.py +0 -14
  157. myokit/tests/test_formats_exporters.py +1 -16
  158. myokit/tests/test_formats_expression_writers.py +1 -17
  159. myokit/tests/test_formats_html.py +0 -3
  160. myokit/tests/test_formats_importers.py +1 -16
  161. myokit/tests/test_formats_mathml_content.py +0 -9
  162. myokit/tests/test_formats_mathml_presentation.py +0 -9
  163. myokit/tests/test_formats_opencl.py +0 -10
  164. myokit/tests/test_formats_sbml.py +0 -15
  165. myokit/tests/test_formats_sympy.py +0 -9
  166. myokit/tests/test_formats_wcp.py +1 -3
  167. myokit/tests/test_io.py +27 -27
  168. myokit/tests/test_jacobian_calculator.py +6 -14
  169. myokit/tests/test_jacobian_tracer.py +0 -9
  170. myokit/tests/test_lib_deps.py +0 -9
  171. myokit/tests/test_lib_guess.py +0 -9
  172. myokit/tests/test_lib_hh.py +18 -12
  173. myokit/tests/test_lib_markov.py +21 -13
  174. myokit/tests/test_lib_multi.py +0 -9
  175. myokit/tests/test_lib_plots.py +13 -8
  176. myokit/tests/test_meta.py +0 -3
  177. myokit/tests/test_model.py +390 -96
  178. myokit/tests/test_model_building.py +44 -96
  179. myokit/tests/test_opencl_info.py +5 -14
  180. myokit/tests/test_pacing_factory.py +0 -3
  181. myokit/tests/test_pacing_system_c.py +1 -23
  182. myokit/tests/test_pacing_system_py.py +0 -9
  183. myokit/tests/test_parsing.py +139 -56
  184. myokit/tests/test_progress_reporters.py +0 -3
  185. myokit/tests/test_protocol.py +0 -9
  186. myokit/tests/test_protocol_floating_point.py +1 -10
  187. myokit/tests/test_protocol_time_series.py +82 -0
  188. myokit/tests/test_pype.py +0 -9
  189. myokit/tests/test_quantity.py +0 -9
  190. myokit/tests/test_rhs_benchmarker.py +1 -9
  191. myokit/tests/test_sbml_api.py +27 -42
  192. myokit/tests/test_sbml_parser.py +4 -19
  193. myokit/tests/test_simulation_1d.py +45 -25
  194. myokit/tests/test_simulation_cvodes.py +321 -55
  195. myokit/tests/test_simulation_cvodes_from_disk.py +0 -3
  196. myokit/tests/test_simulation_fiber_tissue.py +39 -12
  197. myokit/tests/test_simulation_log_interval.py +1 -431
  198. myokit/tests/test_simulation_opencl.py +69 -48
  199. myokit/tests/test_simulation_opencl_log_interval.py +1 -3
  200. myokit/tests/test_simulation_opencl_vs_cvode.py +1 -10
  201. myokit/tests/test_simulation_opencl_vs_sim1d.py +1 -10
  202. myokit/tests/test_system_info.py +1 -11
  203. myokit/tests/test_tools.py +0 -9
  204. myokit/tests/test_unit.py +1 -10
  205. myokit/tests/test_user_functions.py +0 -10
  206. myokit/tests/test_variable.py +231 -27
  207. myokit/tools.py +5 -21
  208. myokit/units.py +5 -3
  209. {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/METADATA +12 -15
  210. myokit-1.35.0.dist-info/RECORD +391 -0
  211. {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/WHEEL +1 -1
  212. {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/entry_points.txt +0 -1
  213. myokit/_exec_new.py +0 -15
  214. myokit/_exec_old.py +0 -15
  215. myokit/_sim/cvodesim.c +0 -1551
  216. myokit/_sim/cvodesim.py +0 -674
  217. myokit/_sim/icsim.cpp +0 -563
  218. myokit/_sim/icsim.py +0 -363
  219. myokit/_sim/psim.cpp +0 -656
  220. myokit/_sim/psim.py +0 -493
  221. myokit/lib/common.py +0 -1094
  222. myokit/tests/test_lib_common.py +0 -130
  223. myokit/tests/test_simulation_cvode.py +0 -612
  224. myokit/tests/test_simulation_ic.py +0 -108
  225. myokit/tests/test_simulation_p.py +0 -223
  226. myokit-1.33.9.dist-info/RECORD +0 -403
  227. /myokit/formats/opencl/template/{test → test.sh} +0 -0
  228. {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/LICENSE.txt +0 -0
  229. {myokit-1.33.9.dist-info → myokit-1.35.0.dist-info}/top_level.txt +0 -0
myokit/_expressions.py CHANGED
@@ -5,26 +5,14 @@
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
-
8
+ import io
11
9
  import math
12
10
  import numpy
13
11
 
14
12
  import myokit
15
- from myokit import IntegrityError
16
13
 
17
- # StringIO in Python 2 and 3
18
- try:
19
- from cStringIO import StringIO
20
- except ImportError:
21
- from io import StringIO
14
+ from myokit import IntegrityError
22
15
 
23
- # Strings in Python 2 and 3
24
- try:
25
- basestring
26
- except NameError: # pragma: no python 2 cover
27
- basestring = str
28
16
 
29
17
  # Expression precedence levels
30
18
  FUNCTION_CALL = 70
@@ -37,7 +25,7 @@ CONDITION_AND = 10
37
25
  LITERAL = 0
38
26
 
39
27
 
40
- class Expression(object):
28
+ class Expression:
41
29
  """
42
30
  Myokit's most generic interface for expressions. All expressions extend
43
31
  this class.
@@ -85,8 +73,8 @@ class Expression(object):
85
73
  self._cached_unit_tolerant = None
86
74
  self._cached_unit_strict = None
87
75
 
88
- def __bool__(self): # pragma: no python 2 cover
89
- """ Python 3 method to determine the outcome of "if expression". """
76
+ def __bool__(self):
77
+ # Determines the outcome of "if expression".
90
78
  return True
91
79
 
92
80
  def bracket(self, op=None):
@@ -142,7 +130,7 @@ class Expression(object):
142
130
  """
143
131
  # Note: Because variable and component names can change, the output of
144
132
  # code can not be cached (for non-literal expressions).
145
- b = StringIO()
133
+ b = io.StringIO()
146
134
  self._code(b, component)
147
135
  return b.getvalue()
148
136
 
@@ -540,8 +528,6 @@ class Expression(object):
540
528
  raise NotImplementedError
541
529
 
542
530
  def __float__(self):
543
- # Cast to float is required in Python 3: numpy float etc. are ok, but
544
- # this is deprecated.
545
531
  return float(self.eval())
546
532
 
547
533
  def __getitem__(self, key):
@@ -551,9 +537,7 @@ class Expression(object):
551
537
  if self._cached_hash is None:
552
538
  self._cached_hash = hash(self._polish())
553
539
  return self._cached_hash
554
- # Note for Python3:
555
- # In Python3, anything that has an __eq__ stops inheriting this hash
556
- # method!
540
+ # Note: anything that has an __eq__ stops inheriting this hash method!
557
541
  # From: https://docs.python.org/3.1/reference/datamodel.html
558
542
  # > If a class that overrides __eq__() needs to retain the
559
543
  # implementation of __hash__() from a parent class, the interpreter
@@ -595,7 +579,7 @@ class Expression(object):
595
579
 
596
580
  def is_literal(self):
597
581
  """
598
- Returns ``True`` if this expression doesn't contain any references.
582
+ Returns ``True`` if this expression does not contain any references.
599
583
  """
600
584
  return len(self._references) == 0
601
585
 
@@ -608,8 +592,10 @@ class Expression(object):
608
592
 
609
593
  def is_number(self, value=None):
610
594
  """
611
- Returns ``True`` only if this expression is a :class:`myokit.Number`
612
- (and has the value ``value``, if given).
595
+ Returns ``True`` only if this expression is a :class:`myokit.Number`.
596
+
597
+ If the optional argument ``value`` is set, it will also return
598
+ ``False`` if the number does not have the given value.
613
599
  """
614
600
  return False
615
601
 
@@ -629,10 +615,6 @@ class Expression(object):
629
615
  def __ne__(self, other):
630
616
  return not self.__eq__(other)
631
617
 
632
- def __nonzero__(self): # pragma: no python 3 cover
633
- """ Python 2 method to determine the outcome of "if expression". """
634
- return True
635
-
636
618
  def operator_rep(self):
637
619
  """
638
620
  Returns a representation of this expression's type. (For example '+' or
@@ -651,7 +633,7 @@ class Expression(object):
651
633
  variable id is immutable in the expression's lifetime.
652
634
  """
653
635
  if self._cached_polish is None:
654
- b = StringIO()
636
+ b = io.StringIO()
655
637
  self._polishb(b)
656
638
  self._cached_polish = b.getvalue()
657
639
  return self._cached_polish
@@ -668,7 +650,7 @@ class Expression(object):
668
650
 
669
651
  def pyfunc(self, use_numpy=True):
670
652
  """
671
- Converts this expression to python and returns the new function's
653
+ Converts this expression to Python and returns the new function's
672
654
  handle.
673
655
 
674
656
  By default, when converting mathematical functions such as ``log``, the
@@ -689,19 +671,19 @@ class Expression(object):
689
671
  # Create function
690
672
  local = {}
691
673
  if use_numpy:
692
- myokit._exec(c, {'numpy': numpy}, local)
674
+ exec(c, {'numpy': numpy}, local)
693
675
  else:
694
- myokit._exec(c, {'math': math}, local)
676
+ exec(c, {'math': math}, local)
695
677
 
696
678
  # Return
697
679
  return local['ex_pyfunc_generated']
698
680
 
699
681
  def pystr(self, use_numpy=False):
700
682
  """
701
- Returns a string representing this expression in python syntax.
683
+ Returns a string representing this expression in Python syntax.
702
684
 
703
685
  By default, built-in functions such as 'exp' are converted to the
704
- python version 'math.exp'. To use the numpy versions, set
686
+ Python version 'math.exp'. To use the numpy versions, set
705
687
  ``numpy=True``.
706
688
  """
707
689
  # Get expression writer
@@ -740,7 +722,7 @@ class Expression(object):
740
722
  Returns a string representing the parse tree corresponding to this
741
723
  expression.
742
724
  """
743
- b = StringIO()
725
+ b = io.StringIO()
744
726
  self._tree_str(b, 0)
745
727
  return b.getvalue()
746
728
 
@@ -853,7 +835,7 @@ class Number(Expression):
853
835
  _rbp = LITERAL
854
836
 
855
837
  def __init__(self, value, unit=None):
856
- super(Number, self).__init__()
838
+ super().__init__()
857
839
  if isinstance(value, myokit.Quantity):
858
840
  # Conversion from Quantity class
859
841
  if unit is not None:
@@ -867,7 +849,7 @@ class Number(Expression):
867
849
  self._value = float(value) if value else 0.0
868
850
  if unit is None or isinstance(unit, myokit.Unit):
869
851
  self._unit = unit
870
- elif isinstance(unit, basestring):
852
+ elif isinstance(unit, str):
871
853
  self._unit = myokit.parse_unit(unit)
872
854
  else:
873
855
  raise ValueError(
@@ -983,7 +965,7 @@ class LhsExpression(Expression):
983
965
  return self.var().is_constant()
984
966
 
985
967
  def is_literal(self):
986
- """See :meth:`Expression.is_constant()`."""
968
+ """See :meth:`Expression.is_literal()`."""
987
969
  return False
988
970
 
989
971
  def rhs(self):
@@ -1011,10 +993,10 @@ class Name(LhsExpression):
1011
993
  *Extends:* :class:`LhsExpression`
1012
994
  """
1013
995
  _rbp = LITERAL
1014
- __hash__ = LhsExpression.__hash__ # For Python3, when __eq__ is present
996
+ __hash__ = LhsExpression.__hash__
1015
997
 
1016
998
  def __init__(self, value):
1017
- super(Name, self).__init__()
999
+ super().__init__()
1018
1000
  self._value = value
1019
1001
  self._references = set([self])
1020
1002
  self._proper = isinstance(self._value, myokit.Variable)
@@ -1052,7 +1034,7 @@ class Name(LhsExpression):
1052
1034
  except KeyError:
1053
1035
  pass
1054
1036
  b.write(self._value.qname(c))
1055
- elif isinstance(self._value, basestring):
1037
+ elif isinstance(self._value, str):
1056
1038
  # Allow strings for debugging
1057
1039
  b.write('str:' + str(self._value))
1058
1040
  else:
@@ -1123,7 +1105,7 @@ class Name(LhsExpression):
1123
1105
  return self._proper and self._value.is_state()
1124
1106
 
1125
1107
  def _polishb(self, b):
1126
- if isinstance(self._value, basestring):
1108
+ if isinstance(self._value, str):
1127
1109
  # Allow an exception for strings
1128
1110
  b.write('str:')
1129
1111
  b.write(self._value)
@@ -1142,7 +1124,7 @@ class Name(LhsExpression):
1142
1124
  """See :meth:`LhsExpression.rhs()`."""
1143
1125
  if self._proper:
1144
1126
  if self._value.is_state():
1145
- return Number(self._value.state_value())
1127
+ return self._value.initial_value()
1146
1128
  elif self._value.lhs() == self:
1147
1129
  return self._value.rhs()
1148
1130
  return None
@@ -1151,7 +1133,7 @@ class Name(LhsExpression):
1151
1133
  b.write(' ' * n + str(self._value) + '\n')
1152
1134
 
1153
1135
  def _validate(self, trail):
1154
- super(Name, self)._validate(trail)
1136
+ super()._validate(trail)
1155
1137
  # Check value: String is allowed at construction for debugging, but
1156
1138
  # not here!
1157
1139
  if not self._proper:
@@ -1172,10 +1154,10 @@ class Derivative(LhsExpression):
1172
1154
  """
1173
1155
  _rbp = FUNCTION_CALL
1174
1156
  _nargs = [1] # Allows parsing as a function
1175
- __hash__ = LhsExpression.__hash__ # For Python3, when __eq__ is present
1157
+ __hash__ = LhsExpression.__hash__
1176
1158
 
1177
1159
  def __init__(self, op):
1178
- super(Derivative, self).__init__((op,))
1160
+ super().__init__((op,))
1179
1161
  if not isinstance(op, Name):
1180
1162
  raise IntegrityError(
1181
1163
  'The dot() operator can only be used on variables.',
@@ -1272,7 +1254,7 @@ class Derivative(LhsExpression):
1272
1254
  return self._op._value
1273
1255
 
1274
1256
  def _validate(self, trail):
1275
- super(Derivative, self)._validate(trail)
1257
+ super()._validate(trail)
1276
1258
  # Check that value is a variable has already been performed by name
1277
1259
  # Check if value is the name of a state variable
1278
1260
  if not self._op._value.is_state():
@@ -1293,7 +1275,7 @@ class PartialDerivative(LhsExpression):
1293
1275
  """
1294
1276
  _rbp = FUNCTION_CALL
1295
1277
  _nargs = [2] # Allows parsing as a function
1296
- __hash__ = LhsExpression.__hash__ # For Python3, when __eq__ is present
1278
+ __hash__ = LhsExpression.__hash__
1297
1279
 
1298
1280
  def __init__(self, var1, var2):
1299
1281
  if not isinstance(var1, (Name, Derivative)):
@@ -1304,7 +1286,7 @@ class PartialDerivative(LhsExpression):
1304
1286
  raise IntegrityError(
1305
1287
  'The second argument to a partial derivative must be a'
1306
1288
  ' variable name or an initial value.')
1307
- super(PartialDerivative, self).__init__((var1, var2))
1289
+ super().__init__((var1, var2))
1308
1290
 
1309
1291
  self._var1 = var1
1310
1292
  self._var2 = var2
@@ -1390,7 +1372,7 @@ class PartialDerivative(LhsExpression):
1390
1372
  As with time-derivatives, this returns the variable of which a
1391
1373
  derivative is taken (i.e. the dependent variable "y" in "dy/dx").
1392
1374
  """
1393
- return self._var1._value
1375
+ return self._var1.var()
1394
1376
 
1395
1377
 
1396
1378
  class InitialValue(LhsExpression):
@@ -1404,13 +1386,13 @@ class InitialValue(LhsExpression):
1404
1386
  """
1405
1387
  _rbp = FUNCTION_CALL
1406
1388
  _nargs = [1] # Allows parsing as a function
1407
- __hash__ = LhsExpression.__hash__ # For Python3, when __eq__ is present
1389
+ __hash__ = LhsExpression.__hash__
1408
1390
 
1409
1391
  def __init__(self, var):
1410
- super(InitialValue, self).__init__((var, ))
1392
+ super().__init__((var, ))
1411
1393
  if not isinstance(var, Name):
1412
1394
  raise IntegrityError(
1413
- 'The first argument to an initial condition must be a variable'
1395
+ 'The first argument to an initial value must be a variable'
1414
1396
  ' name.', self._token)
1415
1397
 
1416
1398
  self._var = var
@@ -1436,7 +1418,7 @@ class InitialValue(LhsExpression):
1436
1418
 
1437
1419
  def _diff(self, lhs, idstates):
1438
1420
  raise NotImplementedError(
1439
- 'Partial derivatives of initial conditions are not supported.')
1421
+ 'Partial derivatives of initial values are not supported.')
1440
1422
 
1441
1423
  def _eval_unit(self, mode):
1442
1424
  return self._var._eval_unit(mode)
@@ -1453,7 +1435,7 @@ class InitialValue(LhsExpression):
1453
1435
  See :meth:`LhsExpression.rhs()`.
1454
1436
 
1455
1437
  The RHS returned in this case will be ``None``, as there is no RHS
1456
- associated with initial conditions in the model.
1438
+ associated with initial values in the model.
1457
1439
  """
1458
1440
  # Note: This _could_ return a Number(init, var unit) instead...
1459
1441
  return None
@@ -1466,12 +1448,12 @@ class InitialValue(LhsExpression):
1466
1448
  return self._var._value
1467
1449
 
1468
1450
  def _validate(self, trail):
1469
- super(InitialValue, self)._validate(trail)
1451
+ super()._validate(trail)
1470
1452
  # Check if value is the name of a state variable
1471
1453
  var = self._var._value
1472
1454
  if not (isinstance(var, myokit.Variable) and var.is_state()):
1473
1455
  raise IntegrityError(
1474
- 'Initial conditions can only be defined for state variables.',
1456
+ 'Initial values can only be defined for state variables.',
1475
1457
  self._token)
1476
1458
 
1477
1459
 
@@ -1485,7 +1467,7 @@ class PrefixExpression(Expression):
1485
1467
  _rep = None
1486
1468
 
1487
1469
  def __init__(self, op):
1488
- super(PrefixExpression, self).__init__((op,))
1470
+ super().__init__((op,))
1489
1471
  self._op = op
1490
1472
 
1491
1473
  def bracket(self, op):
@@ -1584,7 +1566,7 @@ class InfixExpression(Expression):
1584
1566
  _spaces_round_operator = True
1585
1567
 
1586
1568
  def __init__(self, left, right):
1587
- super(InfixExpression, self).__init__((left, right))
1569
+ super().__init__((left, right))
1588
1570
  self._op1 = left
1589
1571
  self._op2 = right
1590
1572
 
@@ -1878,7 +1860,7 @@ class Quotient(InfixExpression):
1878
1860
  #
1879
1861
  # Alternatively, a // b = floor(a / b).
1880
1862
  #
1881
- # Here we ignore the discontinuities in favour of a left or right
1863
+ # Here we ignore the discontinuities in favor of a left or right
1882
1864
  # derivative, and simply return zero for all points.
1883
1865
  return None
1884
1866
 
@@ -2087,7 +2069,7 @@ class Function(Expression):
2087
2069
  _rbp = FUNCTION_CALL
2088
2070
 
2089
2071
  def __init__(self, *ops):
2090
- super(Function, self).__init__(ops)
2072
+ super().__init__(ops)
2091
2073
  if self._nargs is not None:
2092
2074
  if not len(ops) in self._nargs:
2093
2075
  raise IntegrityError(
@@ -2658,7 +2640,7 @@ class If(Function):
2658
2640
  _fname = 'if'
2659
2641
 
2660
2642
  def __init__(self, i, t, e):
2661
- super(If, self).__init__(i, t, e)
2643
+ super().__init__(i, t, e)
2662
2644
  self._i = i # if
2663
2645
  self._t = t # then
2664
2646
  self._e = e # else
@@ -2764,7 +2746,7 @@ class Piecewise(Function):
2764
2746
  _fname = 'piecewise'
2765
2747
 
2766
2748
  def __init__(self, *ops):
2767
- super(Piecewise, self).__init__(*ops)
2749
+ super().__init__(*ops)
2768
2750
 
2769
2751
  # Check number of arguments
2770
2752
  n = len(self._operands)
@@ -2852,7 +2834,7 @@ class Piecewise(Function):
2852
2834
  return iter(self._e)
2853
2835
 
2854
2836
 
2855
- class Condition(object):
2837
+ class Condition:
2856
2838
  """
2857
2839
  *Abstract class*
2858
2840
 
@@ -2866,7 +2848,7 @@ class Condition(object):
2866
2848
  'Conditions do not have partial derivatives.')
2867
2849
 
2868
2850
 
2869
- class PrefixCondition(Condition, PrefixExpression):
2851
+ class PrefixCondition(PrefixExpression, Condition):
2870
2852
  """
2871
2853
  Interface for prefix conditions.
2872
2854
 
@@ -2920,7 +2902,7 @@ class Not(PrefixCondition):
2920
2902
  self._op._polishb(b)
2921
2903
 
2922
2904
 
2923
- class InfixCondition(Condition, InfixExpression):
2905
+ class InfixCondition(InfixExpression, Condition):
2924
2906
  """
2925
2907
  Base class for infix expressions.
2926
2908
 
myokit/_io.py CHANGED
@@ -6,19 +6,11 @@
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 array
10
+ import io
13
11
  import os
14
12
  import sys
15
13
 
16
- # StringIO in Python 2 and 3
17
- try:
18
- from cStringIO import StringIO
19
- except ImportError: # pragma: no python 2 cover
20
- from io import StringIO
21
-
22
14
  import myokit
23
15
 
24
16
 
@@ -93,7 +85,7 @@ def load_script(filename):
93
85
 
94
86
  def load_state(filename, model=None):
95
87
  """
96
- Loads an initial state from a file in one of the formats specified by
88
+ Loads a model state from a file in one of the formats specified by
97
89
  :func:`myokit.parse_state()`.
98
90
 
99
91
  If a :class:`Model` is provided the state will be run through
@@ -110,7 +102,8 @@ def load_state(filename, model=None):
110
102
 
111
103
  def load_state_bin(filename):
112
104
  """
113
- Loads an initial state from a file in the binary format used by myokit.
105
+ Loads a model state from a file in the binary format used by Myokit.
106
+
114
107
  See :meth:`save_state_bin` for details.
115
108
  """
116
109
  filename = os.path.expanduser(filename)
@@ -144,8 +137,6 @@ def load_state_bin(filename):
144
137
  code = parts[1]
145
138
  if code not in ['d', 'f']: # pragma: no cover
146
139
  raise Exception('Invalid state file format [40].')
147
- # Convert code to str for Python 2.7.10 (see #225)
148
- code = str(code)
149
140
 
150
141
  size = int(parts[2])
151
142
  if size < 0: # pragma: no cover
@@ -153,10 +144,7 @@ def load_state_bin(filename):
153
144
 
154
145
  # Create array, read bytes into array
155
146
  ar = array.array(code)
156
- try:
157
- ar.frombytes(f.read(info))
158
- except AttributeError: # pragma: no python 3 cover
159
- ar.fromstring(f.read(info))
147
+ ar.frombytes(f.read(info))
160
148
 
161
149
  # Always store as little endian
162
150
  if sys.byteorder == 'big': # pragma: no cover
@@ -175,11 +163,15 @@ def save(filename=None, model=None, protocol=None, script=None):
175
163
 
176
164
  If no filename is given the ``mmt`` code is returned as a string.
177
165
  """
166
+ if model is None and protocol is None and script is None:
167
+ raise ValueError(
168
+ 'At least one of [model, protocol, script] must not be None.')
169
+
178
170
  if filename:
179
171
  filename = os.path.expanduser(filename)
180
172
  f = open(filename, 'w')
181
173
  else:
182
- f = StringIO()
174
+ f = io.StringIO()
183
175
  out = None
184
176
  try:
185
177
  if model is not None:
@@ -244,7 +236,7 @@ def save_script(filename, script):
244
236
 
245
237
  def save_state(filename, state, model=None):
246
238
  """
247
- Stores the given state in the file at ``filename``.
239
+ Stores a model state to the path ``filename``.
248
240
 
249
241
  If no ``model`` is specified ``state`` should be given as a list of
250
242
  floating point numbers and will be stored by simply placing each number on
@@ -272,8 +264,8 @@ def save_state(filename, state, model=None):
272
264
 
273
265
  def save_state_bin(filename, state, precision=myokit.DOUBLE_PRECISION):
274
266
  """
275
- Stores the given state (or any list of floating point numbers) in the file
276
- at ``filename``, using a binary format.
267
+ Stores a model state (or any given list of floating point numbers) to the
268
+ path ``filename``, using a binary format.
277
269
 
278
270
  The used format is a zip file, containing a single entry: ``state_x_y``,
279
271
  where ``x`` is the used data type (``d`` or ``f``) and ``y`` is the number
@@ -292,8 +284,7 @@ def save_state_bin(filename, state, precision=myokit.DOUBLE_PRECISION):
292
284
  'This method requires the `zlib` module to be installed.')
293
285
 
294
286
  # Data type
295
- # Convert code to str for Python 2.7.10 (see #225)
296
- code = str('d' if precision == myokit.DOUBLE_PRECISION else 'f')
287
+ code = 'd' if precision == myokit.DOUBLE_PRECISION else 'f'
297
288
 
298
289
  # Create array, ensure it's little-endian
299
290
  ar = array.array(code, state)
@@ -306,10 +297,7 @@ def save_state_bin(filename, state, precision=myokit.DOUBLE_PRECISION):
306
297
  info.compress_type = zipfile.ZIP_DEFLATED
307
298
 
308
299
  # Write to compressed file
309
- try:
310
- ar = ar.tobytes()
311
- except AttributeError: # pragma: no python 3 cover
312
- ar = ar.tostring()
300
+ ar = ar.tobytes()
313
301
  with zipfile.ZipFile(filename, 'w') as f:
314
302
  f.writestr(info, ar)
315
303