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.
- psychopy/.DS_Store +0 -0
- psychopy/GIT_SHA +1 -1
- psychopy/VERSION +1 -1
- psychopy/__init__.py +10 -1
- psychopy/__init__.py.orig +65 -0
- psychopy/app/{locale/ar_001/.DS_Store → .DS_Store} +0 -0
- psychopy/app/Resources/.DS_Store +0 -0
- psychopy/app/_psychopyApp.py +11 -3
- psychopy/app/appData.spec +1 -1
- psychopy/app/builder/builder.py +1 -1
- psychopy/app/builder/builder.py.orig +3932 -0
- psychopy/app/builder/dialogs/__init__.py.orig +1679 -0
- psychopy/app/builder/dialogs/paramCtrls.py +1 -1
- psychopy/app/builder/dialogs/paramCtrls.py.orig +713 -0
- psychopy/app/colorpicker/__init__.py.orig +411 -0
- psychopy/app/cortex.log +0 -0
- psychopy/app/jobs.py +8 -1
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +2452 -1731
- psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN.mo +0 -0
- psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN.po +6127 -0
- psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN_allFlagged.mo +0 -0
- psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN_allFlagged.po +7366 -0
- psychopy/app/plugin_manager/dialog.py +9 -7
- psychopy/app/ribbon.py +2 -1
- psychopy/app/runner/runner.py +7 -5
- psychopy/clock.py +8 -4
- psychopy/core.py.orig +169 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/index.html +23 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/randomisedBlocks-legacy-browsers.js +423 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/randomisedBlocks.js +427 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/chooseBlock.xlsx +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/facesBlock.xlsx +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/housesBlock.xlsx +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/face01.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/face02.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/face03.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/house01.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/house02.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/house03.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks.py +330 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks_lastrun.py +330 -0
- psychopy/demos/builder/Feature Demos/eyetracking/eyetracking.xml +298 -0
- psychopy/demos/builder/Feature Demos/eyetracking/eyetracking.xsd +120 -0
- psychopy/demos/builder/Tools/.DS_Store +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/.DS_Store +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.csv +38 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.log +3418 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.psydat +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.csv +2 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.log +15 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.psydat +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual.psyexp +323 -0
- psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual.py +562 -0
- psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual_lastrun.py +562 -0
- psychopy/demos/builder/Tools/gammaCalibration/questStairs.xlsx +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/readme.md +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/resources/low_contrast.png +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/resources/make_2nd_order_tex.py +59 -0
- psychopy/demos/builder/Tools/gammaCalibration/resources/second_order_tex.png +0 -0
- psychopy/demos/coder/.DS_Store +0 -0
- psychopy/demos/coder/experiment control/info_gamma.pickle +0 -0
- psychopy/demos/coder/iohub/.iohpid +1 -0
- psychopy/demos/coder/iohub/eyetracking/.iohpid +1 -0
- psychopy/demos/coder/iohub/wintab/.DS_Store +0 -0
- psychopy/demos/coder/stimuli/.DS_Store +0 -0
- psychopy/demos/coder/stimuli/radialGratingContracting.py +29 -0
- psychopy/experiment/_experiment.py.orig +1032 -0
- psychopy/experiment/components/.DS_Store +0 -0
- psychopy/experiment/components/_base.py +13 -4
- psychopy/experiment/components/_base.py.orig +823 -0
- psychopy/experiment/components/form/.DS_Store +0 -0
- psychopy/experiment/components/microphone/__init__.py +10 -1
- psychopy/experiment/components/microphone/__init__.py.orig +490 -0
- psychopy/experiment/components/polygon/__init__.py +21 -22
- psychopy/experiment/components/settings/__init__.py +13 -14
- psychopy/experiment/components/settings/__init__.py.orig +1337 -0
- psychopy/experiment/components/textbox/__init__.py.orig +310 -0
- psychopy/experiment/components/webcam/.DS_Store +0 -0
- psychopy/experiment/components/webcam/light/.DS_Store +0 -0
- psychopy/experiment/flow.py +10 -8
- psychopy/experiment/loops.py.orig +829 -0
- psychopy/experiment/params.py +8 -3
- psychopy/experiment/params.py.orig +408 -0
- psychopy/experiment/routine.py.orig +503 -0
- psychopy/experiment/routines/_base.py +15 -6
- psychopy/experiment/routines/counterbalance/__init__.py +1 -0
- psychopy/gui/qtgui.py +14 -7
- psychopy/gui/util.py +10 -14
- psychopy/gui/wxgui.py +10 -4
- psychopy/hardware/.DS_Store +0 -0
- psychopy/hardware/brainproducts.py.orig +680 -0
- psychopy/hardware/iolab.py.orig +238 -0
- psychopy/hardware/manager.py +1 -1
- psychopy/hardware/photodiode.py +59 -27
- psychopy/hardware/serialport.py +51 -0
- psychopy/hardware/speaker.py +4 -4
- psychopy/iohub/datastore/__init__.py.orig +443 -0
- psychopy/iohub/datastore/util.py.orig +692 -0
- psychopy/iohub/devices/mouse/darwin.py.orig +427 -0
- psychopy/iohub/devices/mouse/linux2.py.orig +198 -0
- psychopy/preferences/.DS_Store +0 -0
- psychopy/projects/pavlovia.py +10 -3
- psychopy/projects/pavlovia.py.orig +1295 -0
- psychopy/sound/backend_ptb.py +22 -5
- psychopy/sound/transcribe.py +24 -4
- psychopy/tests/.DS_Store +0 -0
- psychopy/tests/data/.DS_Store +0 -0
- psychopy/tests/data/TestCircle_fill_local.png +0 -0
- psychopy/tests/data/__test.png +0 -0
- psychopy/tests/data/aperture1_normHexbackground_local.png +0 -0
- psychopy/tests/data/aperture1_norm_local.png +0 -0
- psychopy/tests/data/aperture2_normHexbackground_local.png +0 -0
- psychopy/tests/data/beatandrcos_height_local.png +0 -0
- psychopy/tests/data/beatandrcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/beatandrcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/beatandrcos_norm_local.png +0 -0
- psychopy/tests/data/beatandrcos_stencil_local.png +0 -0
- psychopy/tests/data/blend_add_height_local.png +0 -0
- psychopy/tests/data/blend_add_normAddBlend_local.png +0 -0
- psychopy/tests/data/blend_add_normHexbackground_local.png +0 -0
- psychopy/tests/data/blend_add_normNoShade_local.png +0 -0
- psychopy/tests/data/blend_add_norm_local.png +0 -0
- psychopy/tests/data/blend_add_stencil_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_height_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_normAddBlend_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_normHexbackground_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_normNoShade_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_norm_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_stencil_local.png +0 -0
- psychopy/tests/data/circleHex_height_local.png +0 -0
- psychopy/tests/data/circleHex_normAddBlend_local.png +0 -0
- psychopy/tests/data/circleHex_normHexbackground_local.png +0 -0
- psychopy/tests/data/circleHex_normNoShade_local.png +0 -0
- psychopy/tests/data/circleHex_norm_local.png +0 -0
- psychopy/tests/data/circleHex_stencil_local.png +0 -0
- psychopy/tests/data/color_comparison_local.png +0 -0
- psychopy/tests/data/corrFullRandom_local.csv +16 -0
- psychopy/tests/data/corrFullRandom_local.tsv +6 -0
- psychopy/tests/data/correctScript/.DS_Store +0 -0
- psychopy/tests/data/dots_height_local.png +0 -0
- psychopy/tests/data/dots_normAddBlend_local.png +0 -0
- psychopy/tests/data/dots_normHexbackground_local.png +0 -0
- psychopy/tests/data/dots_normNoShade_local.png +0 -0
- psychopy/tests/data/dots_norm_local.png +0 -0
- psychopy/tests/data/dots_stencil_local.png +0 -0
- psychopy/tests/data/elarray1_height_local.png +0 -0
- psychopy/tests/data/elarray1_normAddBlend_local.png +0 -0
- psychopy/tests/data/elarray1_normHexbackground_local.png +0 -0
- psychopy/tests/data/elarray1_norm_local.png +0 -0
- psychopy/tests/data/elarray1_stencil_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_height_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_norm_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_stencil_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_height_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_norm_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_stencil_local.png +0 -0
- psychopy/tests/data/gabor1_height_local.png +0 -0
- psychopy/tests/data/gabor1_normAddBlend_local.png +0 -0
- psychopy/tests/data/gabor1_normHexbackground_local.png +0 -0
- psychopy/tests/data/gabor1_normNoShade_local.png +0 -0
- psychopy/tests/data/gabor1_norm_local.png +0 -0
- psychopy/tests/data/gabor1_stencil_local.png +0 -0
- psychopy/tests/data/greyscale_normHexbackground_local.png +0 -0
- psychopy/tests/data/imageAndGauss_height_local.png +0 -0
- psychopy/tests/data/imageAndGauss_normAddBlend_local.png +0 -0
- psychopy/tests/data/imageAndGauss_normHexbackground_local.png +0 -0
- psychopy/tests/data/imageAndGauss_normNoShade_local.png +0 -0
- psychopy/tests/data/imageAndGauss_norm_local.png +0 -0
- psychopy/tests/data/imageAndGauss_stencil_local.png +0 -0
- psychopy/tests/data/movFrame1_stencil_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_height_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_normNoShade_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_norm_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_stencil_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_height_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_normNoShade_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_norm_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_stencil_local.png +0 -0
- psychopy/tests/data/numpyImage_height_local.png +0 -0
- psychopy/tests/data/numpyImage_normAddBlend_local.png +0 -0
- psychopy/tests/data/numpyImage_normHexbackground_local.png +0 -0
- psychopy/tests/data/numpyImage_normNoShade_local.png +0 -0
- psychopy/tests/data/numpyImage_norm_local.png +0 -0
- psychopy/tests/data/numpyImage_stencil_local.png +0 -0
- psychopy/tests/data/shape2_1_normAddBlend_local.png +0 -0
- psychopy/tests/data/shape2_1_normHexbackground_local.png +0 -0
- psychopy/tests/data/shape2_1_normNoShade_local.png +0 -0
- psychopy/tests/data/shape2_1_norm_local.png +0 -0
- psychopy/tests/data/shape2_1_stencil_local.png +0 -0
- psychopy/tests/data/testLoopsBlocks.psyexp_local.py +328 -0
- psychopy/tests/data/text1_height_local.png +0 -0
- psychopy/tests/data/text1_normAddBlend_local.png +0 -0
- psychopy/tests/data/text1_normHexbackground_local.png +0 -0
- psychopy/tests/data/text1_norm_local.png +0 -0
- psychopy/tests/data/text1_stencil_local.png +0 -0
- psychopy/tests/data/text2_height.png +0 -0
- psychopy/tests/data/text2_normAddBlend.png +0 -0
- psychopy/tests/data/text2_normHexbackground.png +0 -0
- psychopy/tests/data/text2_stencil.png +0 -0
- psychopy/tests/data/wedge1_height_local.png +0 -0
- psychopy/tests/data/wedge1_normAddBlend_local.png +0 -0
- psychopy/tests/data/wedge1_normHexbackground_local.png +0 -0
- psychopy/tests/data/wedge1_normNoShade_local.png +0 -0
- psychopy/tests/data/wedge1_norm_local.png +0 -0
- psychopy/tests/data/wedge1_stencil_local.png +0 -0
- psychopy/tests/test_app/.DS_Store +0 -0
- psychopy/tests/test_app/test_builder/.DS_Store +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.csv +9 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.log +177 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.psydat +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.xlsx +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.csv +9 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.log +168 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.psydat +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.xlsx +0 -0
- psychopy/tests/test_data/.DS_Store +0 -0
- psychopy/tests/test_hardware/test_CRS_BitsSharp.py.orig +68 -0
- psychopy/tests/test_tools/test_arraytools.py +112 -0
- psychopy/tests/test_visual/test_image.py.orig +219 -0
- psychopy/tools/arraytools.py +47 -0
- psychopy/tools/versionchooser.py +1 -1
- psychopy/visual/backends/pygletbackend.py +26 -8
- psychopy/visual/basevisual.py.orig +1723 -0
- psychopy/visual/form.py.orig +1181 -0
- psychopy/visual/text.py.orig +752 -0
- psychopy/visual/textbox2/textbox2.py.orig +1315 -0
- psychopy/visual/window.py +13 -5
- psychopy/visual/windowwarp.py.orig +463 -0
- {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/METADATA +9 -9
- {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/RECORD +244 -78
- {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/WHEEL +1 -1
- {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/entry_points.txt +2 -0
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/cs_CZ/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/da_DK/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/de_DE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/el_GR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/en_NZ/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/en_US/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_ES/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/et_EE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fa_IR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fi_FI/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fr_FR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/he_IL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/hi_IN/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/hu_HU/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/it_IT/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ko_KR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ms_MY/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/nl_NL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/nn_NO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pl_PL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pt_PT/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ro_RO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ru_RU/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/sv_SE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/tr_TR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/zh_CN/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/zh_TW/LC_MESSAGE/messages.mo +0 -0
- psychopy-2024.2.1.dist-info/licenses/AUTHORS.md +0 -138
- /psychopy/{app/locale/ar_001/LC_MESSAGE → demos/builder}/.DS_Store +0 -0
- /psychopy/{app/locale/es_ES/LC_MESSAGE → demos/builder/Experiments}/.DS_Store +0 -0
- /psychopy/{visual → demos/builder/Tools/gammaCalibration/data}/.DS_Store +0 -0
- {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
|