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
psychopy/experiment/params.py
CHANGED
|
@@ -51,12 +51,17 @@ inputDefaults = {
|
|
|
51
51
|
'color': 'color',
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
#
|
|
54
|
+
|
|
55
|
+
# these are parameters which once existed but are no longer needed, so inclusion in this list will
|
|
56
|
+
# silence any "future version" warnings
|
|
56
57
|
legacyParams = [
|
|
57
|
-
|
|
58
|
+
# in 2021.1, we standardised colorSpace to be object-wide rather than param-specific
|
|
59
|
+
'lineColorSpace', 'borderColorSpace', 'fillColorSpace', 'foreColorSpace',
|
|
60
|
+
# in 2024.2.0, we removed some superfluous params from the pupil labs backend
|
|
61
|
+
"plCompanionRecordingEnabled", "plPupilCaptureRecordingEnabled",
|
|
58
62
|
]
|
|
59
63
|
|
|
64
|
+
|
|
60
65
|
class Param():
|
|
61
66
|
r"""Defines parameters for Experiment Components
|
|
62
67
|
A string representation of the parameter will depend on the valType:
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
# Part of the PsychoPy library
|
|
5
|
+
# Copyright (C) 2002-2018 Jonathan Peirce (C) 2019-2021 Open Science Tools Ltd.
|
|
6
|
+
# Distributed under the terms of the GNU General Public License (GPL).
|
|
7
|
+
|
|
8
|
+
"""Experiment classes:
|
|
9
|
+
Experiment, Flow, Routine, Param, Loop*, *Handlers, and NameSpace
|
|
10
|
+
|
|
11
|
+
The code that writes out a *_lastrun.py experiment file is (in order):
|
|
12
|
+
experiment.Experiment.writeScript() - starts things off, calls other parts
|
|
13
|
+
settings.SettingsComponent.writeStartCode()
|
|
14
|
+
experiment.Flow.writeBody()
|
|
15
|
+
which will call the .writeBody() methods from each component
|
|
16
|
+
settings.SettingsComponent.writeEndCode()
|
|
17
|
+
"""
|
|
18
|
+
from xml.etree.ElementTree import Element
|
|
19
|
+
|
|
20
|
+
import re
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
from psychopy import logging
|
|
24
|
+
from . import utils
|
|
25
|
+
from . import py2js
|
|
26
|
+
|
|
27
|
+
from ..colors import Color
|
|
28
|
+
from numpy import ndarray
|
|
29
|
+
from ..alerts import alert
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _findParam(name, node):
|
|
33
|
+
"""Searches an XML node in search of a particular param name
|
|
34
|
+
|
|
35
|
+
:param name: str indicating the name of the attribute
|
|
36
|
+
:param node: xml element/node to be searched
|
|
37
|
+
:return: None, or a parameter child node
|
|
38
|
+
"""
|
|
39
|
+
for attr in node:
|
|
40
|
+
if attr.get('name') == name:
|
|
41
|
+
return attr
|
|
42
|
+
|
|
43
|
+
inputDefaults = {
|
|
44
|
+
'str': 'single',
|
|
45
|
+
'code': 'single',
|
|
46
|
+
'num': 'single',
|
|
47
|
+
'bool': 'bool',
|
|
48
|
+
'list': 'single',
|
|
49
|
+
'file': 'file',
|
|
50
|
+
'color': 'color',
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# These are parameters which once existed but are no longer needed, so inclusion in this list will silence any "future
|
|
54
|
+
# version" warnings
|
|
55
|
+
legacyParams = [
|
|
56
|
+
'lineColorSpace', 'borderColorSpace', 'fillColorSpace', 'foreColorSpace', # 2021.1, we standardised colorSpace to be object-wide rather than param-specific
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
class Param():
|
|
60
|
+
r"""Defines parameters for Experiment Components
|
|
61
|
+
A string representation of the parameter will depend on the valType:
|
|
62
|
+
|
|
63
|
+
>>> print(Param(val=[3,4], valType='num'))
|
|
64
|
+
asarray([3, 4])
|
|
65
|
+
>>> print(Param(val=3, valType='num')) # num converts int to float
|
|
66
|
+
3.0
|
|
67
|
+
>>> print(Param(val=3, valType='str') # str keeps as int, converts to code
|
|
68
|
+
3
|
|
69
|
+
>>> print(Param(val='3', valType='str')) # ... and keeps str as str
|
|
70
|
+
'3'
|
|
71
|
+
>>> print(Param(val=[3,4], valType='str')) # val is <type 'list'> -> code
|
|
72
|
+
[3, 4]
|
|
73
|
+
>>> print(Param(val='[3,4]', valType='str'))
|
|
74
|
+
'[3,4]'
|
|
75
|
+
>>> print(Param(val=[3,4], valType='code'))
|
|
76
|
+
[3, 4]
|
|
77
|
+
>>> print(Param(val='"yes", "no"', valType='list'))
|
|
78
|
+
["yes", "no"]
|
|
79
|
+
|
|
80
|
+
>>> #### auto str -> code: at least one non-escaped '$' triggers
|
|
81
|
+
>>> print(Param('[x,y]','str')) # str normally returns string
|
|
82
|
+
'[x,y]'
|
|
83
|
+
>>> print(Param('$[x,y]','str')) # code, as triggered by $
|
|
84
|
+
[x,y]
|
|
85
|
+
>>> print(Param('[$x,$y]','str')) # code, redundant $ ok, cleaned up
|
|
86
|
+
[x,y]
|
|
87
|
+
>>> print(Param('[$x,y]','str')) # code, a $ anywhere means code
|
|
88
|
+
[x,y]
|
|
89
|
+
>>> print(Param('[x,y]$','str')) # ... even at the end
|
|
90
|
+
[x,y]
|
|
91
|
+
>>> print(Param('[x,\$y]','str')) # string, because the only $ is escaped
|
|
92
|
+
'[x,$y]'
|
|
93
|
+
>>> print(Param('[x,\ $y]','str')) # improper escape -> code
|
|
94
|
+
[x,\ y]
|
|
95
|
+
>>> print(Param('/$[x,y]','str')) # improper escape -> code
|
|
96
|
+
/[x,y]
|
|
97
|
+
>>> print(Param('[\$x,$y]','str')) # code, python syntax error
|
|
98
|
+
[$x,y]
|
|
99
|
+
>>> print(Param('["\$x",$y]','str') # ... python syntax ok
|
|
100
|
+
["$x",y]
|
|
101
|
+
>>> print(Param("'$a'",'str')) # code, with the code being a string
|
|
102
|
+
'a'
|
|
103
|
+
>>> print(Param("'\$a'",'str')) # str, with the str containing a str
|
|
104
|
+
"'$a'"
|
|
105
|
+
>>> print(Param('$$$$$myPathologicalVa$$$$$rName','str'))
|
|
106
|
+
myPathologicalVarName
|
|
107
|
+
>>> print(Param('\$$$$$myPathologicalVa$$$$$rName','str'))
|
|
108
|
+
$myPathologicalVarName
|
|
109
|
+
>>> print(Param('$$$$\$myPathologicalVa$$$$$rName','str'))
|
|
110
|
+
$myPathologicalVarName
|
|
111
|
+
>>> print(Param('$$$$\$$$myPathologicalVa$$$\$$$rName','str'))
|
|
112
|
+
$myPathologicalVa$rName
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
def __init__(self, val, valType, inputType=None, allowedVals=None, allowedTypes=None,
|
|
116
|
+
hint="", label="", updates=None, allowedUpdates=None,
|
|
117
|
+
<<<<<<< HEAD
|
|
118
|
+
allowedLabels=None, direct=True,
|
|
119
|
+
=======
|
|
120
|
+
allowedLabels=None,
|
|
121
|
+
canBePath=True,
|
|
122
|
+
>>>>>>> release
|
|
123
|
+
categ="Basic"):
|
|
124
|
+
"""
|
|
125
|
+
@param val: the value for this parameter
|
|
126
|
+
@type val: any
|
|
127
|
+
@param valType: the type of this parameter ('num', 'str', 'code')
|
|
128
|
+
@type valType: string
|
|
129
|
+
@param allowedVals: possible vals for this param
|
|
130
|
+
(e.g. units param can only be 'norm','pix',...)
|
|
131
|
+
@type allowedVals: any
|
|
132
|
+
@param allowedTypes: if other types are allowed then this is
|
|
133
|
+
the possible types this parameter can have
|
|
134
|
+
(e.g. rgb can be 'red' or [1,0,1])
|
|
135
|
+
@type allowedTypes: list
|
|
136
|
+
@param hint: describe this parameter for the user
|
|
137
|
+
@type hint: string
|
|
138
|
+
@param updates: how often does this parameter update
|
|
139
|
+
('experiment', 'routine', 'set every frame')
|
|
140
|
+
@type updates: string
|
|
141
|
+
@param allowedUpdates: conceivable updates for this param
|
|
142
|
+
[None, 'routine', 'set every frame']
|
|
143
|
+
@type allowedUpdates: list
|
|
144
|
+
@param categ: category for this parameter
|
|
145
|
+
will populate tabs in Component Dlg
|
|
146
|
+
@type allowedUpdates: string
|
|
147
|
+
<<<<<<< HEAD
|
|
148
|
+
@param direct: purely used in the test suite, marks whether this
|
|
149
|
+
param's value is expected to appear in the script
|
|
150
|
+
@type direct: bool
|
|
151
|
+
=======
|
|
152
|
+
@param canBePath: is it possible for this parameter to be
|
|
153
|
+
a path? If so, writing as str will check for pathlike
|
|
154
|
+
characters and sanitise if needed.
|
|
155
|
+
@type canBePath: bool
|
|
156
|
+
>>>>>>> release
|
|
157
|
+
"""
|
|
158
|
+
super(Param, self).__init__()
|
|
159
|
+
self.label = label
|
|
160
|
+
self.val = val
|
|
161
|
+
self.valType = valType
|
|
162
|
+
self.allowedTypes = allowedTypes or []
|
|
163
|
+
self.hint = hint
|
|
164
|
+
self.updates = updates
|
|
165
|
+
self.allowedUpdates = allowedUpdates
|
|
166
|
+
self.allowedVals = allowedVals or []
|
|
167
|
+
self.allowedLabels = allowedLabels or []
|
|
168
|
+
self.staticUpdater = None
|
|
169
|
+
self.categ = categ
|
|
170
|
+
self.readOnly = False
|
|
171
|
+
self.codeWanted = False
|
|
172
|
+
<<<<<<< HEAD
|
|
173
|
+
self.direct = direct
|
|
174
|
+
=======
|
|
175
|
+
self.canBePath = canBePath
|
|
176
|
+
>>>>>>> release
|
|
177
|
+
if inputType:
|
|
178
|
+
self.inputType = inputType
|
|
179
|
+
elif valType in inputDefaults:
|
|
180
|
+
self.inputType = inputDefaults[valType]
|
|
181
|
+
else:
|
|
182
|
+
self.inputType = "String"
|
|
183
|
+
|
|
184
|
+
def __str__(self):
|
|
185
|
+
if self.valType == 'num':
|
|
186
|
+
if self.val in [None, ""]:
|
|
187
|
+
return "None"
|
|
188
|
+
try:
|
|
189
|
+
# will work if it can be represented as a float
|
|
190
|
+
return "{}".format(float(self.val))
|
|
191
|
+
except Exception: # might be an array
|
|
192
|
+
return "%s" % self.val
|
|
193
|
+
elif self.valType == 'int':
|
|
194
|
+
try:
|
|
195
|
+
return "%i" % self.val # int and float -> str(int)
|
|
196
|
+
except TypeError:
|
|
197
|
+
return "%s" % self.val # try array of float instead?
|
|
198
|
+
elif self.valType in ['extendedStr','str', 'file', 'table']:
|
|
199
|
+
# at least 1 non-escaped '$' anywhere --> code wanted
|
|
200
|
+
# return str if code wanted
|
|
201
|
+
# return repr if str wanted; this neatly handles "it's" and 'He
|
|
202
|
+
# says "hello"'
|
|
203
|
+
val = self.val
|
|
204
|
+
if isinstance(self.val, str):
|
|
205
|
+
valid, val = self.dollarSyntax()
|
|
206
|
+
if self.codeWanted and valid:
|
|
207
|
+
# If code is wanted, return code (translated to JS if needed)
|
|
208
|
+
if utils.scriptTarget == 'PsychoJS':
|
|
209
|
+
valJS = py2js.expression2js(val)
|
|
210
|
+
if self.val != valJS:
|
|
211
|
+
logging.debug("Rewriting with py2js: {} -> {}".format(self.val, valJS))
|
|
212
|
+
return valJS
|
|
213
|
+
else:
|
|
214
|
+
return val
|
|
215
|
+
else:
|
|
216
|
+
# If str is wanted, return literal
|
|
217
|
+
if utils.scriptTarget != 'PsychoPy':
|
|
218
|
+
if val.startswith("u'") or val.startswith('u"'):
|
|
219
|
+
# if target is python2.x then unicode will be u'something'
|
|
220
|
+
# but for other targets that will raise an annoying error
|
|
221
|
+
val = val[1:]
|
|
222
|
+
# If param is a path or pathlike use Path to make sure it's valid (with / not \)
|
|
223
|
+
isPathLike = bool(re.findall(r"[\\/](?!\W)", val))
|
|
224
|
+
if self.valType in ['file', 'table'] or (isPathLike and self.canBePath):
|
|
225
|
+
val = Path(val).as_posix()
|
|
226
|
+
# Hide escape char on escaped $ (other escaped chars are handled by wx but $ is unique to us)
|
|
227
|
+
val = re.sub(r"\\\$", "$", val)
|
|
228
|
+
# Replace line breaks with escaped line break character
|
|
229
|
+
val = re.sub("\n", "\\n", val)
|
|
230
|
+
return repr(val)
|
|
231
|
+
return repr(self.val)
|
|
232
|
+
elif self.valType in ['code', 'extendedCode']:
|
|
233
|
+
isStr = isinstance(self.val, str)
|
|
234
|
+
if isStr and self.val.startswith("$"):
|
|
235
|
+
# a $ in a code parameter is unnecessary so remove it
|
|
236
|
+
val = "%s" % self.val[1:]
|
|
237
|
+
elif isStr and self.val.startswith(r"\$"):
|
|
238
|
+
# the user actually wanted just the $
|
|
239
|
+
val = "%s" % self.val[1:]
|
|
240
|
+
elif isStr:
|
|
241
|
+
val = "%s" % self.val
|
|
242
|
+
else: # if val was a tuple it needs converting to a string first
|
|
243
|
+
val = "%s" % repr(self.val)
|
|
244
|
+
if utils.scriptTarget == "PsychoJS":
|
|
245
|
+
if self.valType == 'code':
|
|
246
|
+
valJS = py2js.expression2js(val)
|
|
247
|
+
elif self.valType == 'extendedCode':
|
|
248
|
+
valJS = py2js.snippet2js(val)
|
|
249
|
+
if val != valJS:
|
|
250
|
+
logging.debug("Rewriting with py2js: {} -> {}".format(val, valJS))
|
|
251
|
+
return valJS
|
|
252
|
+
else:
|
|
253
|
+
return val
|
|
254
|
+
elif self.valType == 'color':
|
|
255
|
+
_, val = self.dollarSyntax()
|
|
256
|
+
if self.codeWanted:
|
|
257
|
+
# Handle code
|
|
258
|
+
return val
|
|
259
|
+
elif "," in val:
|
|
260
|
+
# Handle lists (e.g. RGB, HSV, etc.)
|
|
261
|
+
val = toList(val)
|
|
262
|
+
return "{}".format(val)
|
|
263
|
+
else:
|
|
264
|
+
# Otherwise, treat as string
|
|
265
|
+
return repr(val)
|
|
266
|
+
elif self.valType == 'list':
|
|
267
|
+
valid, val = self.dollarSyntax()
|
|
268
|
+
val = toList(val)
|
|
269
|
+
return "{}".format(val)
|
|
270
|
+
elif self.valType == 'fixedList':
|
|
271
|
+
return "{}".format(self.val)
|
|
272
|
+
elif self.valType == 'fileList':
|
|
273
|
+
return "{}".format(self.val)
|
|
274
|
+
elif self.valType == 'bool':
|
|
275
|
+
if utils.scriptTarget == "PsychoJS":
|
|
276
|
+
return ("%s" % self.val).lower() # make True -> "true"
|
|
277
|
+
else:
|
|
278
|
+
return "%s" % self.val
|
|
279
|
+
elif self.valType == "table":
|
|
280
|
+
return "%s" % self.val
|
|
281
|
+
elif self.valType == "color":
|
|
282
|
+
if re.match(r"\$", self.val):
|
|
283
|
+
return self.val.strip('$')
|
|
284
|
+
else:
|
|
285
|
+
return f"\"{self.val}\""
|
|
286
|
+
else:
|
|
287
|
+
raise TypeError("Can't represent a Param of type %s" %
|
|
288
|
+
self.valType)
|
|
289
|
+
|
|
290
|
+
def __eq__(self, other):
|
|
291
|
+
"""Test for equivalence is needed for Params because what really
|
|
292
|
+
typically want to test is whether the val is the same
|
|
293
|
+
"""
|
|
294
|
+
return self.val == other
|
|
295
|
+
|
|
296
|
+
def __ne__(self, other):
|
|
297
|
+
"""Test for (non)equivalence is needed for Params because what really
|
|
298
|
+
typically want to test is whether the val is the same/different
|
|
299
|
+
"""
|
|
300
|
+
return self.val != other
|
|
301
|
+
|
|
302
|
+
def __bool__(self):
|
|
303
|
+
"""Return a bool, so we can do `if thisParam`
|
|
304
|
+
rather than `if thisParam.val`"""
|
|
305
|
+
if self.val in ['True', 'true', 'TRUE', True, 1, 1.0]:
|
|
306
|
+
# Return True for aliases of True
|
|
307
|
+
return True
|
|
308
|
+
if self.val in ['False', 'false', 'FALSE', False, 0, 0.0]:
|
|
309
|
+
# Return False for aliases of False
|
|
310
|
+
return False
|
|
311
|
+
# If not a clear alias, use bool method of value
|
|
312
|
+
return bool(self.val)
|
|
313
|
+
|
|
314
|
+
@property
|
|
315
|
+
def xml(self):
|
|
316
|
+
# Make root element
|
|
317
|
+
element = Element('Param')
|
|
318
|
+
# Assign values
|
|
319
|
+
if hasattr(self, 'val'):
|
|
320
|
+
element.set('val', u"{}".format(self.val).replace("\n", " "))
|
|
321
|
+
if hasattr(self, 'valType'):
|
|
322
|
+
element.set('valType', self.valType)
|
|
323
|
+
if hasattr(self, 'updates'):
|
|
324
|
+
element.set('updates', "{}".format(self.updates))
|
|
325
|
+
|
|
326
|
+
return element
|
|
327
|
+
|
|
328
|
+
def dollarSyntax(self):
|
|
329
|
+
"""
|
|
330
|
+
Interpret string according to dollar syntax, return:
|
|
331
|
+
1: Whether syntax is valid (True/False)
|
|
332
|
+
2: Whether code is wanted (True/False)
|
|
333
|
+
3: The value, stripped of any unnecessary $
|
|
334
|
+
"""
|
|
335
|
+
val = self.val
|
|
336
|
+
if self.valType in ['extendedStr','str', 'file', 'table', 'color', 'list']:
|
|
337
|
+
# How to handle dollar signs in a string param
|
|
338
|
+
self.codeWanted = str(val).startswith("$")
|
|
339
|
+
|
|
340
|
+
if not re.search(r"\$", str(val)):
|
|
341
|
+
# Return if there are no $
|
|
342
|
+
return True, val
|
|
343
|
+
if self.codeWanted:
|
|
344
|
+
# If value begins with an unescaped $, remove the first char and treat the rest as code
|
|
345
|
+
val = val[1:]
|
|
346
|
+
inComment = "".join(re.findall(r"\#.*", val))
|
|
347
|
+
inQuotes = "".join(re.findall("[\'\"][^\"|^\']*[\'\"]", val))
|
|
348
|
+
if not re.findall(r"\$", val):
|
|
349
|
+
# Return if there are no further dollar signs
|
|
350
|
+
return True, val
|
|
351
|
+
if len(re.findall(r"\$", val)) == len(re.findall(r"\$", inComment)):
|
|
352
|
+
# Return if all $ are commented out
|
|
353
|
+
return True, val
|
|
354
|
+
if len(re.findall(r"\$", val)) - len(re.findall(r"\$", inComment)) == len(re.findall(r"\\\$", inQuotes)):
|
|
355
|
+
# Return if all non-commended $ are in strings and escaped
|
|
356
|
+
return True, val
|
|
357
|
+
else:
|
|
358
|
+
# If value does not begin with an unescaped $, treat it as a string
|
|
359
|
+
if not re.findall(r"(?<!\\)\$", val):
|
|
360
|
+
# Return if all $ are escaped (\$)
|
|
361
|
+
return True, val
|
|
362
|
+
else:
|
|
363
|
+
# If valType does not interact with $, return True
|
|
364
|
+
return True, val
|
|
365
|
+
# Return false if method has not returned yet
|
|
366
|
+
return False, val
|
|
367
|
+
|
|
368
|
+
__nonzero__ = __bool__ # for python2 compatibility
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def getCodeFromParamStr(val):
|
|
372
|
+
"""Convert a Param.val string to its intended python code
|
|
373
|
+
(as triggered by special char $)
|
|
374
|
+
"""
|
|
375
|
+
tmp = re.sub(r"^(\$)+", '', val) # remove leading $, if any
|
|
376
|
+
# remove all nonescaped $, squash $$$$$
|
|
377
|
+
tmp2 = re.sub(r"([^\\])(\$)+", r"\1", tmp)
|
|
378
|
+
out = re.sub(r"[\\]\$", '$', tmp2) # remove \ from all \$
|
|
379
|
+
if utils.scriptTarget=='PsychoJS':
|
|
380
|
+
out = py2js.expression2js(out)
|
|
381
|
+
return out if out else ''
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def toList(val):
|
|
385
|
+
"""
|
|
386
|
+
|
|
387
|
+
Parameters
|
|
388
|
+
----------
|
|
389
|
+
val
|
|
390
|
+
|
|
391
|
+
Returns
|
|
392
|
+
-------
|
|
393
|
+
A list of entries in the string value
|
|
394
|
+
"""
|
|
395
|
+
if isinstance(val, (list, tuple, ndarray)):
|
|
396
|
+
return val # already a list. Nothing to do
|
|
397
|
+
if isinstance(val, (int, float)):
|
|
398
|
+
return [val] # single value, just needs putting in a cell
|
|
399
|
+
# we really just need to check if they need parentheses
|
|
400
|
+
stripped = val.strip()
|
|
401
|
+
if utils.scriptTarget == "PsychoJS":
|
|
402
|
+
return py2js.expression2js(stripped)
|
|
403
|
+
elif (stripped.startswith('(') and stripped.endswith(')')) or (stripped.startswith('[') and stripped.endswith(']')):
|
|
404
|
+
return stripped
|
|
405
|
+
elif utils.valid_var_re.fullmatch(stripped):
|
|
406
|
+
return "{}".format(stripped)
|
|
407
|
+
else:
|
|
408
|
+
return "[{}]".format(stripped)
|