psychopy 2024.2.1__py3-none-any.whl → 2024.2.4__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.

Potentially problematic release.


This version of psychopy might be problematic. Click here for more details.

Files changed (276) hide show
  1. psychopy/.DS_Store +0 -0
  2. psychopy/GIT_SHA +1 -1
  3. psychopy/VERSION +1 -1
  4. psychopy/__init__.py +10 -1
  5. psychopy/__init__.py.orig +65 -0
  6. psychopy/app/{locale/ar_001/.DS_Store → .DS_Store} +0 -0
  7. psychopy/app/Resources/.DS_Store +0 -0
  8. psychopy/app/_psychopyApp.py +11 -3
  9. psychopy/app/appData.spec +1 -1
  10. psychopy/app/builder/builder.py +1 -1
  11. psychopy/app/builder/builder.py.orig +3932 -0
  12. psychopy/app/builder/dialogs/__init__.py.orig +1679 -0
  13. psychopy/app/builder/dialogs/paramCtrls.py +1 -1
  14. psychopy/app/builder/dialogs/paramCtrls.py.orig +713 -0
  15. psychopy/app/colorpicker/__init__.py.orig +411 -0
  16. psychopy/app/cortex.log +0 -0
  17. psychopy/app/jobs.py +8 -1
  18. psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +2452 -1731
  19. psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN.mo +0 -0
  20. psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN.po +6127 -0
  21. psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN_allFlagged.mo +0 -0
  22. psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN_allFlagged.po +7366 -0
  23. psychopy/app/plugin_manager/dialog.py +9 -7
  24. psychopy/app/ribbon.py +2 -1
  25. psychopy/app/runner/runner.py +7 -5
  26. psychopy/clock.py +8 -4
  27. psychopy/core.py.orig +169 -0
  28. psychopy/demos/builder/Design Templates/randomisedBlocks/html/index.html +23 -0
  29. psychopy/demos/builder/Design Templates/randomisedBlocks/html/randomisedBlocks-legacy-browsers.js +423 -0
  30. psychopy/demos/builder/Design Templates/randomisedBlocks/html/randomisedBlocks.js +427 -0
  31. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/chooseBlock.xlsx +0 -0
  32. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/facesBlock.xlsx +0 -0
  33. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/housesBlock.xlsx +0 -0
  34. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/face01.jpg +0 -0
  35. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/face02.jpg +0 -0
  36. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/face03.jpg +0 -0
  37. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/house01.jpg +0 -0
  38. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/house02.jpg +0 -0
  39. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/house03.jpg +0 -0
  40. psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks.py +330 -0
  41. psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks_lastrun.py +330 -0
  42. psychopy/demos/builder/Feature Demos/eyetracking/eyetracking.xml +298 -0
  43. psychopy/demos/builder/Feature Demos/eyetracking/eyetracking.xsd +120 -0
  44. psychopy/demos/builder/Tools/.DS_Store +0 -0
  45. psychopy/demos/builder/Tools/gammaCalibration/.DS_Store +0 -0
  46. psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.csv +38 -0
  47. psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.log +3418 -0
  48. psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.psydat +0 -0
  49. psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.csv +2 -0
  50. psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.log +15 -0
  51. psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.psydat +0 -0
  52. psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual.psyexp +323 -0
  53. psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual.py +562 -0
  54. psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual_lastrun.py +562 -0
  55. psychopy/demos/builder/Tools/gammaCalibration/questStairs.xlsx +0 -0
  56. psychopy/demos/builder/Tools/gammaCalibration/readme.md +0 -0
  57. psychopy/demos/builder/Tools/gammaCalibration/resources/low_contrast.png +0 -0
  58. psychopy/demos/builder/Tools/gammaCalibration/resources/make_2nd_order_tex.py +59 -0
  59. psychopy/demos/builder/Tools/gammaCalibration/resources/second_order_tex.png +0 -0
  60. psychopy/demos/coder/.DS_Store +0 -0
  61. psychopy/demos/coder/experiment control/info_gamma.pickle +0 -0
  62. psychopy/demos/coder/iohub/.iohpid +1 -0
  63. psychopy/demos/coder/iohub/eyetracking/.iohpid +1 -0
  64. psychopy/demos/coder/iohub/wintab/.DS_Store +0 -0
  65. psychopy/demos/coder/stimuli/.DS_Store +0 -0
  66. psychopy/demos/coder/stimuli/radialGratingContracting.py +29 -0
  67. psychopy/experiment/_experiment.py.orig +1032 -0
  68. psychopy/experiment/components/.DS_Store +0 -0
  69. psychopy/experiment/components/_base.py +13 -4
  70. psychopy/experiment/components/_base.py.orig +823 -0
  71. psychopy/experiment/components/form/.DS_Store +0 -0
  72. psychopy/experiment/components/microphone/__init__.py +10 -1
  73. psychopy/experiment/components/microphone/__init__.py.orig +490 -0
  74. psychopy/experiment/components/polygon/__init__.py +21 -22
  75. psychopy/experiment/components/settings/__init__.py +13 -14
  76. psychopy/experiment/components/settings/__init__.py.orig +1337 -0
  77. psychopy/experiment/components/textbox/__init__.py.orig +310 -0
  78. psychopy/experiment/components/webcam/.DS_Store +0 -0
  79. psychopy/experiment/components/webcam/light/.DS_Store +0 -0
  80. psychopy/experiment/flow.py +10 -8
  81. psychopy/experiment/loops.py.orig +829 -0
  82. psychopy/experiment/params.py +8 -3
  83. psychopy/experiment/params.py.orig +408 -0
  84. psychopy/experiment/routine.py.orig +503 -0
  85. psychopy/experiment/routines/_base.py +15 -6
  86. psychopy/experiment/routines/counterbalance/__init__.py +1 -0
  87. psychopy/gui/qtgui.py +14 -7
  88. psychopy/gui/util.py +10 -14
  89. psychopy/gui/wxgui.py +10 -4
  90. psychopy/hardware/.DS_Store +0 -0
  91. psychopy/hardware/brainproducts.py.orig +680 -0
  92. psychopy/hardware/iolab.py.orig +238 -0
  93. psychopy/hardware/manager.py +1 -1
  94. psychopy/hardware/photodiode.py +59 -27
  95. psychopy/hardware/serialport.py +51 -0
  96. psychopy/hardware/speaker.py +4 -4
  97. psychopy/iohub/datastore/__init__.py.orig +443 -0
  98. psychopy/iohub/datastore/util.py.orig +692 -0
  99. psychopy/iohub/devices/mouse/darwin.py.orig +427 -0
  100. psychopy/iohub/devices/mouse/linux2.py.orig +198 -0
  101. psychopy/preferences/.DS_Store +0 -0
  102. psychopy/projects/pavlovia.py +10 -3
  103. psychopy/projects/pavlovia.py.orig +1295 -0
  104. psychopy/sound/backend_ptb.py +22 -5
  105. psychopy/sound/transcribe.py +24 -4
  106. psychopy/tests/.DS_Store +0 -0
  107. psychopy/tests/data/.DS_Store +0 -0
  108. psychopy/tests/data/TestCircle_fill_local.png +0 -0
  109. psychopy/tests/data/__test.png +0 -0
  110. psychopy/tests/data/aperture1_normHexbackground_local.png +0 -0
  111. psychopy/tests/data/aperture1_norm_local.png +0 -0
  112. psychopy/tests/data/aperture2_normHexbackground_local.png +0 -0
  113. psychopy/tests/data/beatandrcos_height_local.png +0 -0
  114. psychopy/tests/data/beatandrcos_normAddBlend_local.png +0 -0
  115. psychopy/tests/data/beatandrcos_normHexbackground_local.png +0 -0
  116. psychopy/tests/data/beatandrcos_norm_local.png +0 -0
  117. psychopy/tests/data/beatandrcos_stencil_local.png +0 -0
  118. psychopy/tests/data/blend_add_height_local.png +0 -0
  119. psychopy/tests/data/blend_add_normAddBlend_local.png +0 -0
  120. psychopy/tests/data/blend_add_normHexbackground_local.png +0 -0
  121. psychopy/tests/data/blend_add_normNoShade_local.png +0 -0
  122. psychopy/tests/data/blend_add_norm_local.png +0 -0
  123. psychopy/tests/data/blend_add_stencil_local.png +0 -0
  124. psychopy/tests/data/bufferimg_gabor_height_local.png +0 -0
  125. psychopy/tests/data/bufferimg_gabor_normAddBlend_local.png +0 -0
  126. psychopy/tests/data/bufferimg_gabor_normHexbackground_local.png +0 -0
  127. psychopy/tests/data/bufferimg_gabor_normNoShade_local.png +0 -0
  128. psychopy/tests/data/bufferimg_gabor_norm_local.png +0 -0
  129. psychopy/tests/data/bufferimg_gabor_stencil_local.png +0 -0
  130. psychopy/tests/data/circleHex_height_local.png +0 -0
  131. psychopy/tests/data/circleHex_normAddBlend_local.png +0 -0
  132. psychopy/tests/data/circleHex_normHexbackground_local.png +0 -0
  133. psychopy/tests/data/circleHex_normNoShade_local.png +0 -0
  134. psychopy/tests/data/circleHex_norm_local.png +0 -0
  135. psychopy/tests/data/circleHex_stencil_local.png +0 -0
  136. psychopy/tests/data/color_comparison_local.png +0 -0
  137. psychopy/tests/data/corrFullRandom_local.csv +16 -0
  138. psychopy/tests/data/corrFullRandom_local.tsv +6 -0
  139. psychopy/tests/data/correctScript/.DS_Store +0 -0
  140. psychopy/tests/data/dots_height_local.png +0 -0
  141. psychopy/tests/data/dots_normAddBlend_local.png +0 -0
  142. psychopy/tests/data/dots_normHexbackground_local.png +0 -0
  143. psychopy/tests/data/dots_normNoShade_local.png +0 -0
  144. psychopy/tests/data/dots_norm_local.png +0 -0
  145. psychopy/tests/data/dots_stencil_local.png +0 -0
  146. psychopy/tests/data/elarray1_height_local.png +0 -0
  147. psychopy/tests/data/elarray1_normAddBlend_local.png +0 -0
  148. psychopy/tests/data/elarray1_normHexbackground_local.png +0 -0
  149. psychopy/tests/data/elarray1_norm_local.png +0 -0
  150. psychopy/tests/data/elarray1_stencil_local.png +0 -0
  151. psychopy/tests/data/envelopeandrcos_height_local.png +0 -0
  152. psychopy/tests/data/envelopeandrcos_normAddBlend_local.png +0 -0
  153. psychopy/tests/data/envelopeandrcos_normHexbackground_local.png +0 -0
  154. psychopy/tests/data/envelopeandrcos_norm_local.png +0 -0
  155. psychopy/tests/data/envelopeandrcos_stencil_local.png +0 -0
  156. psychopy/tests/data/envelopepowerandrcos_height_local.png +0 -0
  157. psychopy/tests/data/envelopepowerandrcos_normAddBlend_local.png +0 -0
  158. psychopy/tests/data/envelopepowerandrcos_normHexbackground_local.png +0 -0
  159. psychopy/tests/data/envelopepowerandrcos_norm_local.png +0 -0
  160. psychopy/tests/data/envelopepowerandrcos_stencil_local.png +0 -0
  161. psychopy/tests/data/gabor1_height_local.png +0 -0
  162. psychopy/tests/data/gabor1_normAddBlend_local.png +0 -0
  163. psychopy/tests/data/gabor1_normHexbackground_local.png +0 -0
  164. psychopy/tests/data/gabor1_normNoShade_local.png +0 -0
  165. psychopy/tests/data/gabor1_norm_local.png +0 -0
  166. psychopy/tests/data/gabor1_stencil_local.png +0 -0
  167. psychopy/tests/data/greyscale_normHexbackground_local.png +0 -0
  168. psychopy/tests/data/imageAndGauss_height_local.png +0 -0
  169. psychopy/tests/data/imageAndGauss_normAddBlend_local.png +0 -0
  170. psychopy/tests/data/imageAndGauss_normHexbackground_local.png +0 -0
  171. psychopy/tests/data/imageAndGauss_normNoShade_local.png +0 -0
  172. psychopy/tests/data/imageAndGauss_norm_local.png +0 -0
  173. psychopy/tests/data/imageAndGauss_stencil_local.png +0 -0
  174. psychopy/tests/data/movFrame1_stencil_local.png +0 -0
  175. psychopy/tests/data/noiseAndRcos_height_local.png +0 -0
  176. psychopy/tests/data/noiseAndRcos_normAddBlend_local.png +0 -0
  177. psychopy/tests/data/noiseAndRcos_normHexbackground_local.png +0 -0
  178. psychopy/tests/data/noiseAndRcos_normNoShade_local.png +0 -0
  179. psychopy/tests/data/noiseAndRcos_norm_local.png +0 -0
  180. psychopy/tests/data/noiseAndRcos_stencil_local.png +0 -0
  181. psychopy/tests/data/noiseFiltersAndRcos_height_local.png +0 -0
  182. psychopy/tests/data/noiseFiltersAndRcos_normAddBlend_local.png +0 -0
  183. psychopy/tests/data/noiseFiltersAndRcos_normHexbackground_local.png +0 -0
  184. psychopy/tests/data/noiseFiltersAndRcos_normNoShade_local.png +0 -0
  185. psychopy/tests/data/noiseFiltersAndRcos_norm_local.png +0 -0
  186. psychopy/tests/data/noiseFiltersAndRcos_stencil_local.png +0 -0
  187. psychopy/tests/data/numpyImage_height_local.png +0 -0
  188. psychopy/tests/data/numpyImage_normAddBlend_local.png +0 -0
  189. psychopy/tests/data/numpyImage_normHexbackground_local.png +0 -0
  190. psychopy/tests/data/numpyImage_normNoShade_local.png +0 -0
  191. psychopy/tests/data/numpyImage_norm_local.png +0 -0
  192. psychopy/tests/data/numpyImage_stencil_local.png +0 -0
  193. psychopy/tests/data/shape2_1_normAddBlend_local.png +0 -0
  194. psychopy/tests/data/shape2_1_normHexbackground_local.png +0 -0
  195. psychopy/tests/data/shape2_1_normNoShade_local.png +0 -0
  196. psychopy/tests/data/shape2_1_norm_local.png +0 -0
  197. psychopy/tests/data/shape2_1_stencil_local.png +0 -0
  198. psychopy/tests/data/testLoopsBlocks.psyexp_local.py +328 -0
  199. psychopy/tests/data/text1_height_local.png +0 -0
  200. psychopy/tests/data/text1_normAddBlend_local.png +0 -0
  201. psychopy/tests/data/text1_normHexbackground_local.png +0 -0
  202. psychopy/tests/data/text1_norm_local.png +0 -0
  203. psychopy/tests/data/text1_stencil_local.png +0 -0
  204. psychopy/tests/data/text2_height.png +0 -0
  205. psychopy/tests/data/text2_normAddBlend.png +0 -0
  206. psychopy/tests/data/text2_normHexbackground.png +0 -0
  207. psychopy/tests/data/text2_stencil.png +0 -0
  208. psychopy/tests/data/wedge1_height_local.png +0 -0
  209. psychopy/tests/data/wedge1_normAddBlend_local.png +0 -0
  210. psychopy/tests/data/wedge1_normHexbackground_local.png +0 -0
  211. psychopy/tests/data/wedge1_normNoShade_local.png +0 -0
  212. psychopy/tests/data/wedge1_norm_local.png +0 -0
  213. psychopy/tests/data/wedge1_stencil_local.png +0 -0
  214. psychopy/tests/test_app/.DS_Store +0 -0
  215. psychopy/tests/test_app/test_builder/.DS_Store +0 -0
  216. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.csv +9 -0
  217. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.log +177 -0
  218. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.psydat +0 -0
  219. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.xlsx +0 -0
  220. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.csv +9 -0
  221. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.log +168 -0
  222. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.psydat +0 -0
  223. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.xlsx +0 -0
  224. psychopy/tests/test_data/.DS_Store +0 -0
  225. psychopy/tests/test_hardware/test_CRS_BitsSharp.py.orig +68 -0
  226. psychopy/tests/test_tools/test_arraytools.py +112 -0
  227. psychopy/tests/test_visual/test_image.py.orig +219 -0
  228. psychopy/tools/arraytools.py +47 -0
  229. psychopy/tools/versionchooser.py +1 -1
  230. psychopy/visual/backends/pygletbackend.py +26 -8
  231. psychopy/visual/basevisual.py.orig +1723 -0
  232. psychopy/visual/form.py.orig +1181 -0
  233. psychopy/visual/text.py.orig +752 -0
  234. psychopy/visual/textbox2/textbox2.py.orig +1315 -0
  235. psychopy/visual/window.py +13 -5
  236. psychopy/visual/windowwarp.py.orig +463 -0
  237. {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/METADATA +9 -9
  238. {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/RECORD +244 -78
  239. {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/WHEEL +1 -1
  240. {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/entry_points.txt +2 -0
  241. psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
  242. psychopy/app/locale/cs_CZ/LC_MESSAGE/messages.mo +0 -0
  243. psychopy/app/locale/da_DK/LC_MESSAGE/messages.mo +0 -0
  244. psychopy/app/locale/de_DE/LC_MESSAGE/messages.mo +0 -0
  245. psychopy/app/locale/el_GR/LC_MESSAGE/messages.mo +0 -0
  246. psychopy/app/locale/en_NZ/LC_MESSAGE/messages.mo +0 -0
  247. psychopy/app/locale/en_US/LC_MESSAGE/messages.mo +0 -0
  248. psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
  249. psychopy/app/locale/es_ES/LC_MESSAGE/messages.mo +0 -0
  250. psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
  251. psychopy/app/locale/et_EE/LC_MESSAGE/messages.mo +0 -0
  252. psychopy/app/locale/fa_IR/LC_MESSAGE/messages.mo +0 -0
  253. psychopy/app/locale/fi_FI/LC_MESSAGE/messages.mo +0 -0
  254. psychopy/app/locale/fr_FR/LC_MESSAGE/messages.mo +0 -0
  255. psychopy/app/locale/he_IL/LC_MESSAGE/messages.mo +0 -0
  256. psychopy/app/locale/hi_IN/LC_MESSAGE/messages.mo +0 -0
  257. psychopy/app/locale/hu_HU/LC_MESSAGE/messages.mo +0 -0
  258. psychopy/app/locale/it_IT/LC_MESSAGE/messages.mo +0 -0
  259. psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
  260. psychopy/app/locale/ko_KR/LC_MESSAGE/messages.mo +0 -0
  261. psychopy/app/locale/ms_MY/LC_MESSAGE/messages.mo +0 -0
  262. psychopy/app/locale/nl_NL/LC_MESSAGE/messages.mo +0 -0
  263. psychopy/app/locale/nn_NO/LC_MESSAGE/messages.mo +0 -0
  264. psychopy/app/locale/pl_PL/LC_MESSAGE/messages.mo +0 -0
  265. psychopy/app/locale/pt_PT/LC_MESSAGE/messages.mo +0 -0
  266. psychopy/app/locale/ro_RO/LC_MESSAGE/messages.mo +0 -0
  267. psychopy/app/locale/ru_RU/LC_MESSAGE/messages.mo +0 -0
  268. psychopy/app/locale/sv_SE/LC_MESSAGE/messages.mo +0 -0
  269. psychopy/app/locale/tr_TR/LC_MESSAGE/messages.mo +0 -0
  270. psychopy/app/locale/zh_CN/LC_MESSAGE/messages.mo +0 -0
  271. psychopy/app/locale/zh_TW/LC_MESSAGE/messages.mo +0 -0
  272. psychopy-2024.2.1.dist-info/licenses/AUTHORS.md +0 -138
  273. /psychopy/{app/locale/ar_001/LC_MESSAGE → demos/builder}/.DS_Store +0 -0
  274. /psychopy/{app/locale/es_ES/LC_MESSAGE → demos/builder/Experiments}/.DS_Store +0 -0
  275. /psychopy/{visual → demos/builder/Tools/gammaCalibration/data}/.DS_Store +0 -0
  276. {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,443 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # Part of the PsychoPy library
4
+ # Copyright (C) 2012-2020 iSolver Software Solutions (C) 2021 Open Science Tools Ltd.
5
+ # Distributed under the terms of the GNU General Public License (GPL).
6
+
7
+ import os
8
+ import atexit
9
+ import numpy as np
10
+ from pkg_resources import parse_version
11
+ from ..server import DeviceEvent
12
+ from ..constants import EventConstants
13
+ from ..errors import ioHubError, printExceptionDetailsToStdErr, print2err
14
+
15
+ import tables
16
+ from tables import parameters, StringCol, UInt32Col, UInt16Col, NoSuchNodeError
17
+
18
+ if parse_version(tables.__version__) < parse_version('3'):
19
+ from tables import openFile as open_file
20
+
21
+ create_table = "createTable"
22
+ create_group = "createGroup"
23
+ f_get_child = "_f_getChild"
24
+ else:
25
+ from tables import open_file
26
+
27
+ create_table = "create_table"
28
+ create_group = "create_group"
29
+ _f_get_child = "_f_get_child"
30
+
31
+ parameters.MAX_NUMEXPR_THREADS = None
32
+ """The maximum number of threads that PyTables should use internally in
33
+ Numexpr. If `None`, it is automatically set to the number of cores in
34
+ your machine."""
35
+
36
+ parameters.MAX_BLOSC_THREADS = None
37
+ """The maximum number of threads that PyTables should use internally in
38
+ Blosc. If `None`, it is automatically set to the number of cores in
39
+ your machine."""
40
+
41
+ DATA_FILE_TITLE = "ioHub DataStore - Experiment Data File."
42
+ FILE_VERSION = '0.9.1.2'
43
+ SCHEMA_AUTHORS = 'Sol Simpson'
44
+ SCHEMA_MODIFIED_DATE = 'October 27, 2021'
45
+
46
+
47
+ class DataStoreFile():
48
+ def __init__(self, fileName, folderPath, fmode='a', iohub_settings=None):
49
+ self.fileName = fileName
50
+ self.folderPath = folderPath
51
+ self.filePath = os.path.join(folderPath, fileName)
52
+
53
+ if iohub_settings.get('multiple_sessions', False) is False:
54
+ fmode = 'w'
55
+
56
+ self.settings = iohub_settings
57
+
58
+ self.active_experiment_id = None
59
+ self.active_session_id = None
60
+
61
+ self.flushCounter = self.settings.get('flush_interval', 32)
62
+ self._eventCounter = 0
63
+
64
+ self.TABLES = dict()
65
+ self._eventGroupMappings = dict()
66
+ self.emrtFile = open_file(self.filePath, mode=fmode)
67
+
68
+ atexit.register(close_open_data_files, False)
69
+
70
+ if len(self.emrtFile.title) == 0:
71
+ self.buildOutTemplate()
72
+ self.flush()
73
+ else:
74
+ self.loadTableMappings()
75
+
76
+ def loadTableMappings(self):
77
+ # create meta-data tables
78
+ self.TABLES['EXPERIMENT_METADETA'] = self.emrtFile.root.data_collection.experiment_meta_data
79
+ self.TABLES['SESSION_METADETA'] = self.emrtFile.root.data_collection.session_meta_data
80
+ self.TABLES['CLASS_TABLE_MAPPINGS'] = self.emrtFile.root.class_table_mapping
81
+
82
+ def buildOutTemplate(self):
83
+ self.emrtFile.title = DATA_FILE_TITLE
84
+ self.emrtFile.FILE_VERSION = FILE_VERSION
85
+ self.emrtFile.SCHEMA_DESIGNER = SCHEMA_AUTHORS
86
+ self.emrtFile.SCHEMA_MODIFIED = SCHEMA_MODIFIED_DATE
87
+
88
+ create_group_func = getattr(self.emrtFile, create_group)
89
+ create_table_func = getattr(self.emrtFile, create_table)
90
+
91
+ # CREATE GROUPS
92
+ self.TABLES['CLASS_TABLE_MAPPINGS'] = create_table_func(self.emrtFile.root, 'class_table_mapping',
93
+ ClassTableMappings, title='ioHub DeviceEvent Class to '
94
+ 'DataStore Table Mappings.')
95
+
96
+ create_group_func(self.emrtFile.root, 'data_collection', title='Data collected using ioHub.')
97
+ self.flush()
98
+
99
+ create_group_func(self.emrtFile.root.data_collection, 'events', title='Events collected using ioHub.')
100
+
101
+ create_group_func(self.emrtFile.root.data_collection, 'condition_variables', title="Experiment Condition "
102
+ "Variable Data.")
103
+ self.flush()
104
+
105
+ self.TABLES['EXPERIMENT_METADETA'] = create_table_func(self.emrtFile.root.data_collection,
106
+ 'experiment_meta_data', ExperimentMetaData,
107
+ title='Experiment Metadata.')
108
+
109
+ self.TABLES['SESSION_METADETA'] = create_table_func(self.emrtFile.root.data_collection, 'session_meta_data',
110
+ SessionMetaData, title='Session Metadata.')
111
+ self.flush()
112
+
113
+ create_group_func(self.emrtFile.root.data_collection.events, 'experiment', title='Experiment Device Events.')
114
+ create_group_func(self.emrtFile.root.data_collection.events, 'keyboard', title='Keyboard Device Events.')
115
+ create_group_func(self.emrtFile.root.data_collection.events, 'mouse', title='Mouse Device Events.')
116
+ create_group_func(self.emrtFile.root.data_collection.events, 'wintab', title='Wintab Device Events.')
117
+ create_group_func(self.emrtFile.root.data_collection.events, 'eyetracker', title='EyeTracker Device Events.')
118
+ create_group_func(self.emrtFile.root.data_collection.events, 'serial', title='Serial Interface Events.')
119
+ create_group_func(self.emrtFile.root.data_collection.events, 'pstbox', title='Serial Pstbox Device Events.')
120
+
121
+ self.flush()
122
+
123
+ @staticmethod
124
+ def eventTableLabel2ClassName(event_table_label):
125
+ tokens = str(event_table_label[0] + event_table_label[1:].lower() + 'Event').split('_')
126
+ return ''.join([t[0].upper() + t[1:] for t in tokens])
127
+
128
+ def groupNodeForEvent(self, event_cls):
129
+ evt_group_label = event_cls.PARENT_DEVICE.DEVICE_TYPE_STRING.lower()
130
+ datevts_node = self.emrtFile.root.data_collection.events
131
+ try:
132
+ # If group for event table already exists return it....
133
+ return datevts_node._f_get_child(evt_group_label)
134
+ except tables.NoSuchNodeError:
135
+ # Create the group node for the event....
136
+ egtitle = "%s%s Device Events." % (evt_group_label[0].upper(), evt_group_label[1:])
137
+ self.emrtFile.createGroup(datevts_node, evt_group_label, title=egtitle)
138
+ return datevts_node._f_get_child(evt_group_label)
139
+
140
+ def updateDataStoreStructure(self, device_instance, event_class_dict):
141
+ dfilter = tables.Filters(complevel=0, complib='zlib', shuffle=False, fletcher32=False)
142
+
143
+ for event_cls_name, event_cls in event_class_dict.items():
144
+ if event_cls.IOHUB_DATA_TABLE:
145
+ table_label = event_cls.IOHUB_DATA_TABLE
146
+ if table_label not in self.TABLES:
147
+ try:
148
+ tc_name = self.eventTableLabel2ClassName(table_label)
149
+ create_table_func = getattr(self.emrtFile, create_table)
150
+ dc_name = device_instance.__class__.__name__
151
+ self.TABLES[table_label] = create_table_func(self.groupNodeForEvent(event_cls),
152
+ tc_name,
153
+ event_cls.NUMPY_DTYPE,
154
+ title='%s Data' % dc_name,
155
+ filters=dfilter.copy())
156
+ self.flush()
157
+ except tables.NodeError:
158
+ self.TABLES[table_label] = self.groupNodeForEvent(event_cls)._f_get_child(tc_name)
159
+ except Exception as e:
160
+ print2err('---------------ERROR------------------')
161
+ print2err('Exception %s in iohub.datastore.updateDataStoreStructure:' % (e.__class__.__name__))
162
+ print2err('\tevent_cls: {0}'.format(event_cls))
163
+ print2err('\tevent_cls_name: {0}'.format(event_cls_name))
164
+ print2err('\tevent_table_label: {0}'.format(table_label))
165
+ print2err('\teventTable2ClassName: {0}'.format(tc_name))
166
+ print2err('\tgroupNodeForEvent(event_cls): {0}'.format(self.groupNodeForEvent(event_cls)))
167
+ print2err('\nException:')
168
+ printExceptionDetailsToStdErr()
169
+ print2err('--------------------------------------')
170
+
171
+ if table_label in self.TABLES:
172
+ self.addClassMapping(event_cls, self.TABLES[table_label])
173
+ else:
174
+ print2err('---- IOHUB.DATASTORE CANNOT ADD CLASS MAPPING ----')
175
+ print2err('\t** TABLES missing key: {0}'.format(table_label))
176
+ print2err('\tevent_cls: {0}'.format(event_cls))
177
+ print2err('\tevent_cls_name: {0}'.format(event_cls_name))
178
+ print2err('\teventTableLabel2ClassName: {0}'.format(self.eventTableLabel2ClassName(table_label)))
179
+ print2err('----------------------------------------------')
180
+
181
+ def addClassMapping(self, ioClass, ctable):
182
+ cmtable = self.TABLES['CLASS_TABLE_MAPPINGS']
183
+ names = [x['class_id'] for x in cmtable.where('(class_id == %d)' % ioClass.EVENT_TYPE_ID)]
184
+ if len(names) == 0:
185
+ trow = cmtable.row
186
+ trow['class_id'] = ioClass.EVENT_TYPE_ID
187
+ trow['class_type_id'] = 1 # Device or Event etc.
188
+ trow['class_name'] = ioClass.__name__
189
+ trow['table_path'] = ctable._v_pathname
190
+ trow.append()
191
+ self.flush()
192
+
193
+ def createOrUpdateExperimentEntry(self, experimentInfoList):
194
+ experiment_metadata = self.TABLES['EXPERIMENT_METADETA']
195
+ result = [row for row in experiment_metadata.iterrows() if row['code'] == experimentInfoList[1]]
196
+ if len(result) > 0:
197
+ result = result[0]
198
+ self.active_experiment_id = result['experiment_id']
199
+ return self.active_experiment_id
200
+ max_id = 0
201
+ id_col = experiment_metadata.col('experiment_id')
202
+ if len(id_col) > 0:
203
+ max_id = np.amax(id_col)
204
+ self.active_experiment_id = max_id + 1
205
+ experimentInfoList[0] = self.active_experiment_id
206
+ experiment_metadata.append([tuple(experimentInfoList), ])
207
+ self.flush()
208
+ return self.active_experiment_id
209
+
210
+ def createExperimentSessionEntry(self, sessionInfoDict):
211
+ session_metadata = self.TABLES['SESSION_METADETA']
212
+ max_id = 0
213
+ id_col = session_metadata.col('session_id')
214
+ if len(id_col) > 0:
215
+ max_id = np.amax(id_col)
216
+ self.active_session_id = int(max_id + 1)
217
+
218
+ values = (self.active_session_id, self.active_experiment_id, sessionInfoDict['code'], sessionInfoDict['name'],
219
+ sessionInfoDict['comments'], sessionInfoDict['user_variables'])
220
+
221
+ session_metadata.append([values, ])
222
+ self.flush()
223
+ return self.active_session_id
224
+
225
+ def initConditionVariableTable(
226
+ self, experiment_id, session_id, np_dtype):
227
+ expcv_table = None
228
+ exp_session = [('EXPERIMENT_ID', 'i4'), ('SESSION_ID', 'i4')]
229
+ exp_session.extend(np_dtype)
230
+ np_dtype = []
231
+ for npctype in exp_session:
232
+ if isinstance(npctype[0], str):
233
+ nv = [str(npctype[0]), ]
234
+ nv.extend(npctype[1:])
235
+ np_dtype.append(tuple(nv))
236
+ else:
237
+ np_dtype.append(npctype)
238
+
239
+ np_dtype2 = []
240
+ for adtype in np_dtype:
241
+ adtype2 = []
242
+ for a in adtype:
243
+ if isinstance(a, bytes):
244
+ a = str(a, 'utf-8')
245
+ adtype2.append(a)
246
+ np_dtype2.append(tuple(adtype2))
247
+ np_dtype = np_dtype2
248
+ self._EXP_COND_DTYPE = np.dtype(np_dtype)
249
+ try:
250
+ expCondTableName = "EXP_CV_%d" % (experiment_id)
251
+ experimentConditionVariableTable = getattr(self.emrtFile.root.data_collection.condition_variables,
252
+ _f_get_child)(expCondTableName)
253
+ self.TABLES['EXP_CV'] = experimentConditionVariableTable
254
+ except NoSuchNodeError:
255
+ try:
256
+ experimentConditionVariableTable = getattr(self.emrtFile, create_table)(
257
+ self.emrtFile.root.data_collection.condition_variables, expCondTableName, self._EXP_COND_DTYPE,
258
+ title='Condition Variable Values for Experiment ID %d' % experiment_id)
259
+ self.TABLES['EXP_CV'] = experimentConditionVariableTable
260
+ self.emrtFile.flush()
261
+ except Exception:
262
+ printExceptionDetailsToStdErr()
263
+ return False
264
+ except Exception:
265
+ print2err('Error getting expcv_table for experiment %d, table name: %s' % (experiment_id, expCondTableName))
266
+ printExceptionDetailsToStdErr()
267
+ return False
268
+ self._activeRunTimeConditionVariableTable = expcv_table
269
+ return True
270
+
271
+ def extendConditionVariableTable(self, experiment_id, session_id, data):
272
+ if self._EXP_COND_DTYPE is None:
273
+ return False
274
+ if self.emrtFile and 'EXP_CV' in self.TABLES:
275
+ temp = [experiment_id, session_id]
276
+ temp.extend(data)
277
+ data = temp
278
+ try:
279
+ etable = self.TABLES['EXP_CV']
280
+ for i, d in enumerate(data):
281
+ if isinstance(d, (list, tuple)):
282
+ data[i] = tuple(d)
283
+ np_array = np.array([tuple(data), ], dtype=self._EXP_COND_DTYPE)
284
+ etable.append(np_array)
285
+ self.bufferedFlush()
286
+ return True
287
+ except Exception:
288
+ printExceptionDetailsToStdErr()
289
+ return False
290
+
291
+ def checkForExperimentAndSessionIDs(self, event=None):
292
+ if self.active_experiment_id is None or self.active_session_id is None:
293
+ exp_id = self.active_experiment_id
294
+ if exp_id is None:
295
+ exp_id = 0
296
+ sess_id = self.active_session_id
297
+ if sess_id is None:
298
+ sess_id = 0
299
+ return False
300
+ return True
301
+
302
+ def checkIfSessionCodeExists(self, sessionCode):
303
+ if self.emrtFile:
304
+ wclause = 'experiment_id == %d' % (self.active_experiment_id,)
305
+ sessionsForExperiment = self.emrtFile.root.data_collection.session_meta_data.where(wclause)
306
+ sessionCodeMatch = [sess for sess in sessionsForExperiment if sess['code'] == sessionCode]
307
+ if len(sessionCodeMatch) > 0:
308
+ return True
309
+ return False
310
+
311
+ def _handleEvent(self, event):
312
+ try:
313
+ if self.checkForExperimentAndSessionIDs(event) is False:
314
+ return False
315
+ etype = event[DeviceEvent.EVENT_TYPE_ID_INDEX]
316
+ eventClass = EventConstants.getClass(etype)
317
+ etable = self.TABLES[eventClass.IOHUB_DATA_TABLE]
318
+ event[DeviceEvent.EVENT_EXPERIMENT_ID_INDEX] = self.active_experiment_id
319
+ event[DeviceEvent.EVENT_SESSION_ID_INDEX] = self.active_session_id
320
+
321
+ np_array = np.array([tuple(event), ], dtype=eventClass.NUMPY_DTYPE)
322
+ etable.append(np_array)
323
+ self.bufferedFlush()
324
+ except Exception:
325
+ print2err("Error saving event: ", event)
326
+ printExceptionDetailsToStdErr()
327
+
328
+ def _handleEvents(self, events):
329
+ try:
330
+ if self.checkForExperimentAndSessionIDs(len(events)) is False:
331
+ return False
332
+
333
+ event = events[0]
334
+
335
+ etype = event[DeviceEvent.EVENT_TYPE_ID_INDEX]
336
+ eventClass = EventConstants.getClass(etype)
337
+ etable = self.TABLES[eventClass.IOHUB_DATA_TABLE]
338
+
339
+ np_events = []
340
+ for event in events:
341
+ event[DeviceEvent.EVENT_EXPERIMENT_ID_INDEX] = self.active_experiment_id
342
+ event[DeviceEvent.EVENT_SESSION_ID_INDEX] = self.active_session_id
343
+ np_events.append(tuple(event))
344
+
345
+ np_array = np.array(np_events, dtype=eventClass.NUMPY_DTYPE)
346
+ etable.append(np_array)
347
+ self.bufferedFlush(len(np_events))
348
+ except ioHubError as e:
349
+ print2err(e)
350
+ except Exception:
351
+ printExceptionDetailsToStdErr()
352
+
353
+ def bufferedFlush(self, eventCount=1):
354
+ """
355
+ If flushCounter threshold is >=0 then do some checks. If it is < 0,
356
+ then flush only occurs when command is sent to ioHub,
357
+ so do nothing here.
358
+ """
359
+ if self.flushCounter >= 0:
360
+ if self.flushCounter == 0:
361
+ self.flush()
362
+ return True
363
+ if self.flushCounter <= self._eventCounter:
364
+ self.flush()
365
+ self._eventCounter = 0
366
+ return True
367
+ self._eventCounter += eventCount
368
+ return False
369
+
370
+ def flush(self):
371
+ try:
372
+ if self.emrtFile:
373
+ self.emrtFile.flush()
374
+ except tables.ClosedFileError:
375
+ pass
376
+ except Exception:
377
+ printExceptionDetailsToStdErr()
378
+
379
+ def close(self):
380
+ self.flush()
381
+ self._activeRunTimeConditionVariableTable = None
382
+ self.emrtFile.close()
383
+
384
+ def __del__(self):
385
+ try:
386
+ self.close()
387
+ except Exception:
388
+ pass
389
+
390
+
391
+ ## -------------------- Utility Functions ------------------------ ##
392
+
393
+
394
+ def close_open_data_files(verbose):
395
+ open_files = tables.file._open_files
396
+ clall = hasattr(open_files, 'close_all')
397
+ if clall:
398
+ open_files.close_all()
399
+ else:
400
+ are_open_files = len(open_files) > 0
401
+ if verbose and are_open_files:
402
+ print2err('Closing remaining open data files:')
403
+ for fileh in open_files:
404
+ if verbose:
405
+ print2err('%s...' % (open_files[fileh].filename,))
406
+ open_files[fileh].close()
407
+ if verbose:
408
+ print2err('done')
409
+
410
+
411
+ registered_close_open_data_files = True
412
+ atexit.register(close_open_data_files, False)
413
+
414
+
415
+ ## ---------------------- Pytable Definitions ------------------- ##
416
+
417
+
418
+ class ClassTableMappings(tables.IsDescription):
419
+ class_id = UInt32Col(pos=1)
420
+ class_type_id = UInt32Col(pos=2) # Device or Event etc.
421
+ class_name = StringCol(32, pos=3)
422
+ table_path = StringCol(128, pos=4)
423
+
424
+
425
+ class ExperimentMetaData(tables.IsDescription):
426
+ experiment_id = UInt32Col(pos=1)
427
+ code = StringCol(256, pos=2)
428
+ title = StringCol(256, pos=3)
429
+ description = StringCol(4096, pos=4)
430
+ version = StringCol(32, pos=5)
431
+
432
+
433
+ class SessionMetaData(tables.IsDescription):
434
+ session_id = UInt32Col(pos=1)
435
+ experiment_id = UInt32Col(pos=2)
436
+ code = StringCol(256, pos=3)
437
+ name = StringCol(256, pos=4)
438
+ comments = StringCol(4096, pos=5)
439
+ <<<<<<< HEAD
440
+ user_variables = StringCol(16384, pos=6) # Holds json encoded version of user variable dict for session
441
+ =======
442
+ user_variables = StringCol(16384, pos=6) # Holds json encoded version of user variable dict for session
443
+ >>>>>>> release