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/_config.py CHANGED
@@ -5,27 +5,18 @@
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
- # Load Myokit, at least, the bit that's been setup so far. This just means
12
- # this method will add a link to the myokit module already being loaded
13
- # into this method's namespace. This allows us to use the constants defined
14
- # before this method was called.
15
- import myokit
16
-
17
- # Load standard library modules
8
+ import configparser
18
9
  import logging
19
10
  import os
20
11
  import platform
21
12
  import sys
22
13
  import warnings
23
14
 
24
- # ConfigParser in Python 2 and 3
25
- try:
26
- from ConfigParser import ConfigParser
27
- except ImportError:
28
- from configparser import RawConfigParser as ConfigParser
15
+ # Load Myokit, at least, the bit that's been setup so far. This just means
16
+ # this method will add a link to the myokit module already being loaded
17
+ # into this method's namespace. This allows us to use the constants defined
18
+ # before this method was called.
19
+ import myokit
29
20
 
30
21
 
31
22
  def _create(path):
@@ -37,7 +28,7 @@ def _create(path):
37
28
  system = platform.system()
38
29
 
39
30
  # Create config parser
40
- config = ConfigParser(allow_no_value=True)
31
+ config = configparser.RawConfigParser(allow_no_value=True)
41
32
 
42
33
  # Make the parser case sensitive (need for unix paths!)
43
34
  config.optionxform = str
@@ -71,12 +62,12 @@ def _create(path):
71
62
  # GUI Backend
72
63
  config.add_section('gui')
73
64
  config.set('gui', '# Backend to use for graphical user interface.')
74
- config.set('gui', '# Valid options are pyqt5, pyqt4, pyside2 and pyside.')
65
+ config.set('gui', '# Valid options are pyqt6, pyqt5, pyside6 and pyside2.')
75
66
  config.set('gui', '# Leave unset for automatic selection.')
67
+ config.set('gui', '#backend = pyqt6')
76
68
  config.set('gui', '#backend = pyqt5')
77
- config.set('gui', '#backend = pyqt4')
69
+ config.set('gui', '#backend = pyside6')
78
70
  config.set('gui', '#backend = pyside2')
79
- config.set('gui', '#backend = pyside')
80
71
 
81
72
  # Locations of sundials library
82
73
  config.add_section('sundials')
@@ -223,7 +214,7 @@ def _load():
223
214
  del lines, inline_comment
224
215
 
225
216
  # Create the config parser (no value allows comments)
226
- config = ConfigParser(allow_no_value=True)
217
+ config = configparser.RawConfigParser(allow_no_value=True)
227
218
 
228
219
  # Make the parser case sensitive (need for unix paths!)
229
220
  config.optionxform = str
@@ -270,30 +261,30 @@ def _load():
270
261
  # GUI Backend
271
262
  if config.has_option('gui', 'backend'):
272
263
  x = config.get('gui', 'backend').strip().lower()
273
- if x == 'pyqt' or x == 'pyqt4':
274
- myokit.FORCE_PYQT4 = True
264
+ if x == 'pyqt6':
265
+ myokit.FORCE_PYQT6 = True
275
266
  myokit.FORCE_PYQT5 = False
276
- myokit.FORCE_PYSIDE = False
267
+ myokit.FORCE_PYSIDE6 = False
277
268
  myokit.FORCE_PYSIDE2 = False
278
269
  elif x == 'pyqt5':
279
- myokit.FORCE_PYQT4 = False
270
+ myokit.FORCE_PYQT6 = False
280
271
  myokit.FORCE_PYQT5 = True
281
- myokit.FORCE_PYSIDE = False
272
+ myokit.FORCE_PYSIDE6 = False
282
273
  myokit.FORCE_PYSIDE2 = False
283
- elif x == 'pyside':
284
- myokit.FORCE_PYQT4 = False
274
+ elif x == 'pyside6':
275
+ myokit.FORCE_PYQT6 = False
285
276
  myokit.FORCE_PYQT5 = False
286
- myokit.FORCE_PYSIDE = True
277
+ myokit.FORCE_PYSIDE6 = True
287
278
  myokit.FORCE_PYSIDE2 = False
288
279
  elif x == 'pyside2':
289
- myokit.FORCE_PYQT4 = False
280
+ myokit.FORCE_PYQT6 = False
290
281
  myokit.FORCE_PYQT5 = False
291
- myokit.FORCE_PYSIDE = False
282
+ myokit.FORCE_PYSIDE6 = False
292
283
  myokit.FORCE_PYSIDE2 = True
293
284
  elif x != '':
294
285
  warnings.warn(
295
286
  'Invalid setting in myokit.ini. Expected values for backend'
296
- ' are pyqt, pyqt4, pyqt5, pyside, or pyside2. Got: ' + x)
287
+ ' are pyqt6, pyqt5, pyside6, or pyside2. Got: ' + x)
297
288
 
298
289
  # Sundials libraries, header files, and version
299
290
  if config.has_option('sundials', 'lib'):
myokit/_datablock.py CHANGED
@@ -4,15 +4,14 @@
4
4
  # This file is part of Myokit.
5
5
  # See http://myokit.org for copyright, sharing, and licensing details.
6
6
  #
7
- from __future__ import absolute_import, division
8
- from __future__ import print_function, unicode_literals
9
-
7
+ import array
10
8
  import os
11
9
  import sys
12
- import array
13
- import numpy as np
10
+
14
11
  import myokit
15
12
 
13
+ import numpy as np
14
+
16
15
 
17
16
  # Readme file for DataBlock1d binary files
18
17
  README_SAVE_1D = """
@@ -85,7 +84,7 @@ header, and little-endian:
85
84
  ENC = 'utf-8'
86
85
 
87
86
 
88
- class DataBlock1d(object):
87
+ class DataBlock1d:
89
88
  """
90
89
  Container for time-series of 1d rectangular data arrays.
91
90
 
@@ -187,8 +186,8 @@ class DataBlock1d(object):
187
186
  ' of cells.')
188
187
 
189
188
  # Get indices of selected cells
190
- ilo = border # First indice
191
- ihi = self._nx - border # Last indice + 1
189
+ ilo = border # First index
190
+ ihi = self._nx - border # Last index + 1
192
191
 
193
192
  # Indices of cells with AP
194
193
  i1 = None
@@ -205,8 +204,8 @@ class DataBlock1d(object):
205
204
  t = []
206
205
  for i in range(ilo, ihi):
207
206
  v = v_series[i]
208
- # Get indice of first threshold crossing with positive flank
209
- # Don't include crossings at log indice 0
207
+ # Get index of first threshold crossing with positive flank
208
+ # Don't include crossings at log index 0
210
209
  itime = np.where((v[1:] > -30) & (v[1:] - v[:-1] > 0))[0]
211
210
  if len(itime) == 0 or itime[0] == 0:
212
211
  # No crossing found
@@ -476,17 +475,10 @@ class DataBlock1d(object):
476
475
  'This method requires the ``zlib`` module to be installed.')
477
476
 
478
477
  # Get size of single and double types on this machine
479
- try:
480
- dsize = {
481
- 'd': len(array.array('d', [1]).tobytes()),
482
- 'f': len(array.array('f', [1]).tobytes()),
483
- }
484
- except (AttributeError, TypeError): # pragma: no python 3 cover
485
- # List dtype as str for Python 2.7.10 (see #225)
486
- dsize = {
487
- b'd': len(array.array(b'd', [1]).tostring()),
488
- b'f': len(array.array(b'f', [1]).tostring()),
489
- }
478
+ dsize = {
479
+ 'd': len(array.array('d', [1]).tobytes()),
480
+ 'f': len(array.array('f', [1]).tobytes()),
481
+ }
490
482
 
491
483
  # Read data from file
492
484
  try:
@@ -544,8 +536,6 @@ class DataBlock1d(object):
544
536
  nt = int(next(head))
545
537
  nx = int(next(head))
546
538
  dtype = next(head)[1:-1]
547
- # Convert dtype to str for Python 2.7.10 (see #225)
548
- dtype = str(dtype)
549
539
  if dtype not in dsize:
550
540
  raise myokit.DataBlockReadError(
551
541
  'Unable to read DataBlock1d: Unrecognized data type "'
@@ -573,10 +563,7 @@ class DataBlock1d(object):
573
563
  'Unable to read DataBlock1d: Header indicates larger data'
574
564
  ' than found in the body.')
575
565
  data = array.array(dtype)
576
- try:
577
- data.frombytes(body[start:end])
578
- except AttributeError: # pragma: no python 3 cover
579
- data.fromstring(body[start:end])
566
+ data.frombytes(body[start:end])
580
567
  if sys.byteorder == 'big': # pragma: no cover
581
568
  data.byteswap()
582
569
  data = np.array(data)
@@ -597,10 +584,7 @@ class DataBlock1d(object):
597
584
  'Unable to read DataBlock1d: Header indicates larger'
598
585
  ' data than found in the body.')
599
586
  data = array.array(dtype)
600
- try:
601
- data.frombytes(body[start:end])
602
- except AttributeError: # pragma: no python 3 cover
603
- data.fromstring(body[start:end])
587
+ data.frombytes(body[start:end])
604
588
  if sys.byteorder == 'big': # pragma: no cover
605
589
  data.byteswap()
606
590
  data = np.array(data)
@@ -619,10 +603,7 @@ class DataBlock1d(object):
619
603
  'Unable to read DataBlock1d: Header indicates larger'
620
604
  ' data than found in the body.')
621
605
  data = array.array(dtype)
622
- try:
623
- data.frombytes(body[start:end])
624
- except AttributeError: # pragma: no python 3 cover
625
- data.fromstring(body[start:end])
606
+ data.frombytes(body[start:end])
626
607
  if sys.byteorder == 'big': # pragma: no cover
627
608
  data.byteswap()
628
609
  data = np.array(data).reshape(nt, nx, order='C')
@@ -680,8 +661,7 @@ class DataBlock1d(object):
680
661
  'This method requires the ``zlib`` module to be installed.')
681
662
 
682
663
  # Data type
683
- # Create dtype as str for Python 2.7.10 (see #225)
684
- dtype = str('d') # Only supporting doubles right now
664
+ dtype = 'd' # Only supporting doubles right now
685
665
 
686
666
  # Create header
687
667
  head_str = []
@@ -706,10 +686,7 @@ class DataBlock1d(object):
706
686
  if sys.byteorder == 'big': # pragma: no cover
707
687
  for ar in body_str:
708
688
  ar.byteswap()
709
- try:
710
- body_str = b''.join([ar.tobytes() for ar in body_str])
711
- except AttributeError: # pragma: no python 3 cover
712
- body_str = b''.join([ar.tostring() for ar in body_str])
689
+ body_str = b''.join([ar.tobytes() for ar in body_str])
713
690
 
714
691
  # Write
715
692
  head = zipfile.ZipInfo('header_block1d.txt')
@@ -803,7 +780,7 @@ class DataBlock1d(object):
803
780
  return self._1d[variable][:, x]
804
781
 
805
782
 
806
- class DataBlock2d(object):
783
+ class DataBlock2d:
807
784
  """
808
785
  Container for time-series of 2d rectangular data arrays.
809
786
 
@@ -1274,17 +1251,10 @@ class DataBlock2d(object):
1274
1251
  'This method requires the ``zlib`` module to be installed.')
1275
1252
 
1276
1253
  # Get size of single and double types on this machine
1277
- try:
1278
- dsize = {
1279
- 'd': len(array.array('d', [1]).tobytes()),
1280
- 'f': len(array.array('f', [1]).tobytes()),
1281
- }
1282
- except (AttributeError, TypeError): # pragma: no python 3 cover
1283
- # List dtype as str for Python 2.7.10 (see #225)
1284
- dsize = {
1285
- b'd': len(array.array(b'd', [1]).tostring()),
1286
- b'f': len(array.array(b'f', [1]).tostring()),
1287
- }
1254
+ dsize = {
1255
+ 'd': len(array.array('d', [1]).tobytes()),
1256
+ 'f': len(array.array('f', [1]).tobytes()),
1257
+ }
1288
1258
 
1289
1259
  # Read data from file
1290
1260
  try:
@@ -1353,8 +1323,7 @@ class DataBlock2d(object):
1353
1323
  nx = int(next(head))
1354
1324
 
1355
1325
  # Get dtype
1356
- # Convert dtype to str for Python 2.7.10 (see #225)
1357
- dtype = str(next(head))[1:-1]
1326
+ dtype = next(head)[1:-1]
1358
1327
  if dtype not in dsize:
1359
1328
  raise myokit.DataBlockReadError(
1360
1329
  'Unable to read DataBlock2d: Unrecognized data type "'
@@ -1384,10 +1353,7 @@ class DataBlock2d(object):
1384
1353
  ' than found in the body.')
1385
1354
 
1386
1355
  data = array.array(dtype)
1387
- try:
1388
- data.frombytes(body[start:end])
1389
- except AttributeError: # pragma: no python 3 cover
1390
- data.fromstring(body[start:end])
1356
+ data.frombytes(body[start:end])
1391
1357
  if sys.byteorder == 'big': # pragma: no cover
1392
1358
  data.byteswap()
1393
1359
  data = np.array(data)
@@ -1408,10 +1374,7 @@ class DataBlock2d(object):
1408
1374
  'Unable to read DataBlock2d: Header indicates larger'
1409
1375
  ' data than found in the body.')
1410
1376
  data = array.array(dtype)
1411
- try:
1412
- data.frombytes(body[start:end])
1413
- except AttributeError: # pragma: no python 3 cover
1414
- data.fromstring(body[start:end])
1377
+ data.frombytes(body[start:end])
1415
1378
  if sys.byteorder == 'big': # pragma: no cover
1416
1379
  data.byteswap()
1417
1380
  data = np.array(data)
@@ -1430,10 +1393,7 @@ class DataBlock2d(object):
1430
1393
  'Unable to read DataBlock2d: Header indicates larger'
1431
1394
  ' data than found in the body.')
1432
1395
  data = array.array(dtype)
1433
- try:
1434
- data.frombytes(body[start:end])
1435
- except AttributeError: # pragma: no python 3 cover
1436
- data.fromstring(body[start:end])
1396
+ data.frombytes(body[start:end])
1437
1397
  if sys.byteorder == 'big': # pragma: no cover
1438
1398
  data.byteswap()
1439
1399
  data = np.array(data).reshape(nt, ny, nx, order='C')
@@ -1496,8 +1456,7 @@ class DataBlock2d(object):
1496
1456
  'This method requires the ``zlib`` module to be installed.')
1497
1457
 
1498
1458
  # Data type
1499
- # Create dtype as str for Python 2.7.10 (see #225)
1500
- dtype = str('d') # Only supporting doubles right now
1459
+ dtype = 'd' # Only supporting doubles right now
1501
1460
 
1502
1461
  # Create header
1503
1462
  head_str = []
@@ -1523,10 +1482,7 @@ class DataBlock2d(object):
1523
1482
  if sys.byteorder == 'big': # pragma: no cover
1524
1483
  for ar in body_str:
1525
1484
  ar.byteswap()
1526
- try:
1527
- body_str = b''.join([ar.tobytes() for ar in body_str])
1528
- except AttributeError: # pragma: no python 3 cover
1529
- body_str = b''.join([ar.tostring() for ar in body_str])
1485
+ body_str = b''.join([ar.tobytes() for ar in body_str])
1530
1486
 
1531
1487
  # Write
1532
1488
  head = zipfile.ZipInfo('header_block2d.txt')
@@ -1671,7 +1627,7 @@ class DataBlock2d(object):
1671
1627
  return self._2d[variable][:, y, x]
1672
1628
 
1673
1629
 
1674
- class ColorMap(object):
1630
+ class ColorMap:
1675
1631
  """
1676
1632
  *Abstract class*
1677
1633