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
@@ -51,12 +51,17 @@ inputDefaults = {
51
51
  'color': 'color',
52
52
  }
53
53
 
54
- # These are parameters which once existed but are no longer needed, so inclusion in this list will silence any "future
55
- # version" warnings
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
- 'lineColorSpace', 'borderColorSpace', 'fillColorSpace', 'foreColorSpace', # 2021.1, we standardised colorSpace to be object-wide rather than param-specific
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", "&#10;"))
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)