psychopy 2024.2.1__py3-none-any.whl → 2024.2.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (276) hide show
  1. psychopy/.DS_Store +0 -0
  2. psychopy/GIT_SHA +1 -1
  3. psychopy/VERSION +1 -1
  4. psychopy/__init__.py +10 -1
  5. psychopy/__init__.py.orig +65 -0
  6. psychopy/app/{locale/ar_001/.DS_Store → .DS_Store} +0 -0
  7. psychopy/app/Resources/.DS_Store +0 -0
  8. psychopy/app/_psychopyApp.py +11 -3
  9. psychopy/app/appData.spec +1 -1
  10. psychopy/app/builder/builder.py +1 -1
  11. psychopy/app/builder/builder.py.orig +3932 -0
  12. psychopy/app/builder/dialogs/__init__.py.orig +1679 -0
  13. psychopy/app/builder/dialogs/paramCtrls.py +1 -1
  14. psychopy/app/builder/dialogs/paramCtrls.py.orig +713 -0
  15. psychopy/app/colorpicker/__init__.py.orig +411 -0
  16. psychopy/app/cortex.log +0 -0
  17. psychopy/app/jobs.py +8 -1
  18. psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +2452 -1731
  19. psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN.mo +0 -0
  20. psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN.po +6127 -0
  21. psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN_allFlagged.mo +0 -0
  22. psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN_allFlagged.po +7366 -0
  23. psychopy/app/plugin_manager/dialog.py +9 -7
  24. psychopy/app/ribbon.py +2 -1
  25. psychopy/app/runner/runner.py +7 -5
  26. psychopy/clock.py +8 -4
  27. psychopy/core.py.orig +169 -0
  28. psychopy/demos/builder/Design Templates/randomisedBlocks/html/index.html +23 -0
  29. psychopy/demos/builder/Design Templates/randomisedBlocks/html/randomisedBlocks-legacy-browsers.js +423 -0
  30. psychopy/demos/builder/Design Templates/randomisedBlocks/html/randomisedBlocks.js +427 -0
  31. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/chooseBlock.xlsx +0 -0
  32. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/facesBlock.xlsx +0 -0
  33. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/housesBlock.xlsx +0 -0
  34. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/face01.jpg +0 -0
  35. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/face02.jpg +0 -0
  36. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/face03.jpg +0 -0
  37. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/house01.jpg +0 -0
  38. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/house02.jpg +0 -0
  39. psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/house03.jpg +0 -0
  40. psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks.py +330 -0
  41. psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks_lastrun.py +330 -0
  42. psychopy/demos/builder/Feature Demos/eyetracking/eyetracking.xml +298 -0
  43. psychopy/demos/builder/Feature Demos/eyetracking/eyetracking.xsd +120 -0
  44. psychopy/demos/builder/Tools/.DS_Store +0 -0
  45. psychopy/demos/builder/Tools/gammaCalibration/.DS_Store +0 -0
  46. psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.csv +38 -0
  47. psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.log +3418 -0
  48. psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.psydat +0 -0
  49. psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.csv +2 -0
  50. psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.log +15 -0
  51. psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.psydat +0 -0
  52. psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual.psyexp +323 -0
  53. psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual.py +562 -0
  54. psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual_lastrun.py +562 -0
  55. psychopy/demos/builder/Tools/gammaCalibration/questStairs.xlsx +0 -0
  56. psychopy/demos/builder/Tools/gammaCalibration/readme.md +0 -0
  57. psychopy/demos/builder/Tools/gammaCalibration/resources/low_contrast.png +0 -0
  58. psychopy/demos/builder/Tools/gammaCalibration/resources/make_2nd_order_tex.py +59 -0
  59. psychopy/demos/builder/Tools/gammaCalibration/resources/second_order_tex.png +0 -0
  60. psychopy/demos/coder/.DS_Store +0 -0
  61. psychopy/demos/coder/experiment control/info_gamma.pickle +0 -0
  62. psychopy/demos/coder/iohub/.iohpid +1 -0
  63. psychopy/demos/coder/iohub/eyetracking/.iohpid +1 -0
  64. psychopy/demos/coder/iohub/wintab/.DS_Store +0 -0
  65. psychopy/demos/coder/stimuli/.DS_Store +0 -0
  66. psychopy/demos/coder/stimuli/radialGratingContracting.py +29 -0
  67. psychopy/experiment/_experiment.py.orig +1032 -0
  68. psychopy/experiment/components/.DS_Store +0 -0
  69. psychopy/experiment/components/_base.py +13 -4
  70. psychopy/experiment/components/_base.py.orig +823 -0
  71. psychopy/experiment/components/form/.DS_Store +0 -0
  72. psychopy/experiment/components/microphone/__init__.py +10 -1
  73. psychopy/experiment/components/microphone/__init__.py.orig +490 -0
  74. psychopy/experiment/components/polygon/__init__.py +21 -22
  75. psychopy/experiment/components/settings/__init__.py +13 -14
  76. psychopy/experiment/components/settings/__init__.py.orig +1337 -0
  77. psychopy/experiment/components/textbox/__init__.py.orig +310 -0
  78. psychopy/experiment/components/webcam/.DS_Store +0 -0
  79. psychopy/experiment/components/webcam/light/.DS_Store +0 -0
  80. psychopy/experiment/flow.py +10 -8
  81. psychopy/experiment/loops.py.orig +829 -0
  82. psychopy/experiment/params.py +8 -3
  83. psychopy/experiment/params.py.orig +408 -0
  84. psychopy/experiment/routine.py.orig +503 -0
  85. psychopy/experiment/routines/_base.py +15 -6
  86. psychopy/experiment/routines/counterbalance/__init__.py +1 -0
  87. psychopy/gui/qtgui.py +14 -7
  88. psychopy/gui/util.py +10 -14
  89. psychopy/gui/wxgui.py +10 -4
  90. psychopy/hardware/.DS_Store +0 -0
  91. psychopy/hardware/brainproducts.py.orig +680 -0
  92. psychopy/hardware/iolab.py.orig +238 -0
  93. psychopy/hardware/manager.py +1 -1
  94. psychopy/hardware/photodiode.py +59 -27
  95. psychopy/hardware/serialport.py +51 -0
  96. psychopy/hardware/speaker.py +4 -4
  97. psychopy/iohub/datastore/__init__.py.orig +443 -0
  98. psychopy/iohub/datastore/util.py.orig +692 -0
  99. psychopy/iohub/devices/mouse/darwin.py.orig +427 -0
  100. psychopy/iohub/devices/mouse/linux2.py.orig +198 -0
  101. psychopy/preferences/.DS_Store +0 -0
  102. psychopy/projects/pavlovia.py +10 -3
  103. psychopy/projects/pavlovia.py.orig +1295 -0
  104. psychopy/sound/backend_ptb.py +22 -5
  105. psychopy/sound/transcribe.py +24 -4
  106. psychopy/tests/.DS_Store +0 -0
  107. psychopy/tests/data/.DS_Store +0 -0
  108. psychopy/tests/data/TestCircle_fill_local.png +0 -0
  109. psychopy/tests/data/__test.png +0 -0
  110. psychopy/tests/data/aperture1_normHexbackground_local.png +0 -0
  111. psychopy/tests/data/aperture1_norm_local.png +0 -0
  112. psychopy/tests/data/aperture2_normHexbackground_local.png +0 -0
  113. psychopy/tests/data/beatandrcos_height_local.png +0 -0
  114. psychopy/tests/data/beatandrcos_normAddBlend_local.png +0 -0
  115. psychopy/tests/data/beatandrcos_normHexbackground_local.png +0 -0
  116. psychopy/tests/data/beatandrcos_norm_local.png +0 -0
  117. psychopy/tests/data/beatandrcos_stencil_local.png +0 -0
  118. psychopy/tests/data/blend_add_height_local.png +0 -0
  119. psychopy/tests/data/blend_add_normAddBlend_local.png +0 -0
  120. psychopy/tests/data/blend_add_normHexbackground_local.png +0 -0
  121. psychopy/tests/data/blend_add_normNoShade_local.png +0 -0
  122. psychopy/tests/data/blend_add_norm_local.png +0 -0
  123. psychopy/tests/data/blend_add_stencil_local.png +0 -0
  124. psychopy/tests/data/bufferimg_gabor_height_local.png +0 -0
  125. psychopy/tests/data/bufferimg_gabor_normAddBlend_local.png +0 -0
  126. psychopy/tests/data/bufferimg_gabor_normHexbackground_local.png +0 -0
  127. psychopy/tests/data/bufferimg_gabor_normNoShade_local.png +0 -0
  128. psychopy/tests/data/bufferimg_gabor_norm_local.png +0 -0
  129. psychopy/tests/data/bufferimg_gabor_stencil_local.png +0 -0
  130. psychopy/tests/data/circleHex_height_local.png +0 -0
  131. psychopy/tests/data/circleHex_normAddBlend_local.png +0 -0
  132. psychopy/tests/data/circleHex_normHexbackground_local.png +0 -0
  133. psychopy/tests/data/circleHex_normNoShade_local.png +0 -0
  134. psychopy/tests/data/circleHex_norm_local.png +0 -0
  135. psychopy/tests/data/circleHex_stencil_local.png +0 -0
  136. psychopy/tests/data/color_comparison_local.png +0 -0
  137. psychopy/tests/data/corrFullRandom_local.csv +16 -0
  138. psychopy/tests/data/corrFullRandom_local.tsv +6 -0
  139. psychopy/tests/data/correctScript/.DS_Store +0 -0
  140. psychopy/tests/data/dots_height_local.png +0 -0
  141. psychopy/tests/data/dots_normAddBlend_local.png +0 -0
  142. psychopy/tests/data/dots_normHexbackground_local.png +0 -0
  143. psychopy/tests/data/dots_normNoShade_local.png +0 -0
  144. psychopy/tests/data/dots_norm_local.png +0 -0
  145. psychopy/tests/data/dots_stencil_local.png +0 -0
  146. psychopy/tests/data/elarray1_height_local.png +0 -0
  147. psychopy/tests/data/elarray1_normAddBlend_local.png +0 -0
  148. psychopy/tests/data/elarray1_normHexbackground_local.png +0 -0
  149. psychopy/tests/data/elarray1_norm_local.png +0 -0
  150. psychopy/tests/data/elarray1_stencil_local.png +0 -0
  151. psychopy/tests/data/envelopeandrcos_height_local.png +0 -0
  152. psychopy/tests/data/envelopeandrcos_normAddBlend_local.png +0 -0
  153. psychopy/tests/data/envelopeandrcos_normHexbackground_local.png +0 -0
  154. psychopy/tests/data/envelopeandrcos_norm_local.png +0 -0
  155. psychopy/tests/data/envelopeandrcos_stencil_local.png +0 -0
  156. psychopy/tests/data/envelopepowerandrcos_height_local.png +0 -0
  157. psychopy/tests/data/envelopepowerandrcos_normAddBlend_local.png +0 -0
  158. psychopy/tests/data/envelopepowerandrcos_normHexbackground_local.png +0 -0
  159. psychopy/tests/data/envelopepowerandrcos_norm_local.png +0 -0
  160. psychopy/tests/data/envelopepowerandrcos_stencil_local.png +0 -0
  161. psychopy/tests/data/gabor1_height_local.png +0 -0
  162. psychopy/tests/data/gabor1_normAddBlend_local.png +0 -0
  163. psychopy/tests/data/gabor1_normHexbackground_local.png +0 -0
  164. psychopy/tests/data/gabor1_normNoShade_local.png +0 -0
  165. psychopy/tests/data/gabor1_norm_local.png +0 -0
  166. psychopy/tests/data/gabor1_stencil_local.png +0 -0
  167. psychopy/tests/data/greyscale_normHexbackground_local.png +0 -0
  168. psychopy/tests/data/imageAndGauss_height_local.png +0 -0
  169. psychopy/tests/data/imageAndGauss_normAddBlend_local.png +0 -0
  170. psychopy/tests/data/imageAndGauss_normHexbackground_local.png +0 -0
  171. psychopy/tests/data/imageAndGauss_normNoShade_local.png +0 -0
  172. psychopy/tests/data/imageAndGauss_norm_local.png +0 -0
  173. psychopy/tests/data/imageAndGauss_stencil_local.png +0 -0
  174. psychopy/tests/data/movFrame1_stencil_local.png +0 -0
  175. psychopy/tests/data/noiseAndRcos_height_local.png +0 -0
  176. psychopy/tests/data/noiseAndRcos_normAddBlend_local.png +0 -0
  177. psychopy/tests/data/noiseAndRcos_normHexbackground_local.png +0 -0
  178. psychopy/tests/data/noiseAndRcos_normNoShade_local.png +0 -0
  179. psychopy/tests/data/noiseAndRcos_norm_local.png +0 -0
  180. psychopy/tests/data/noiseAndRcos_stencil_local.png +0 -0
  181. psychopy/tests/data/noiseFiltersAndRcos_height_local.png +0 -0
  182. psychopy/tests/data/noiseFiltersAndRcos_normAddBlend_local.png +0 -0
  183. psychopy/tests/data/noiseFiltersAndRcos_normHexbackground_local.png +0 -0
  184. psychopy/tests/data/noiseFiltersAndRcos_normNoShade_local.png +0 -0
  185. psychopy/tests/data/noiseFiltersAndRcos_norm_local.png +0 -0
  186. psychopy/tests/data/noiseFiltersAndRcos_stencil_local.png +0 -0
  187. psychopy/tests/data/numpyImage_height_local.png +0 -0
  188. psychopy/tests/data/numpyImage_normAddBlend_local.png +0 -0
  189. psychopy/tests/data/numpyImage_normHexbackground_local.png +0 -0
  190. psychopy/tests/data/numpyImage_normNoShade_local.png +0 -0
  191. psychopy/tests/data/numpyImage_norm_local.png +0 -0
  192. psychopy/tests/data/numpyImage_stencil_local.png +0 -0
  193. psychopy/tests/data/shape2_1_normAddBlend_local.png +0 -0
  194. psychopy/tests/data/shape2_1_normHexbackground_local.png +0 -0
  195. psychopy/tests/data/shape2_1_normNoShade_local.png +0 -0
  196. psychopy/tests/data/shape2_1_norm_local.png +0 -0
  197. psychopy/tests/data/shape2_1_stencil_local.png +0 -0
  198. psychopy/tests/data/testLoopsBlocks.psyexp_local.py +328 -0
  199. psychopy/tests/data/text1_height_local.png +0 -0
  200. psychopy/tests/data/text1_normAddBlend_local.png +0 -0
  201. psychopy/tests/data/text1_normHexbackground_local.png +0 -0
  202. psychopy/tests/data/text1_norm_local.png +0 -0
  203. psychopy/tests/data/text1_stencil_local.png +0 -0
  204. psychopy/tests/data/text2_height.png +0 -0
  205. psychopy/tests/data/text2_normAddBlend.png +0 -0
  206. psychopy/tests/data/text2_normHexbackground.png +0 -0
  207. psychopy/tests/data/text2_stencil.png +0 -0
  208. psychopy/tests/data/wedge1_height_local.png +0 -0
  209. psychopy/tests/data/wedge1_normAddBlend_local.png +0 -0
  210. psychopy/tests/data/wedge1_normHexbackground_local.png +0 -0
  211. psychopy/tests/data/wedge1_normNoShade_local.png +0 -0
  212. psychopy/tests/data/wedge1_norm_local.png +0 -0
  213. psychopy/tests/data/wedge1_stencil_local.png +0 -0
  214. psychopy/tests/test_app/.DS_Store +0 -0
  215. psychopy/tests/test_app/test_builder/.DS_Store +0 -0
  216. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.csv +9 -0
  217. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.log +177 -0
  218. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.psydat +0 -0
  219. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.xlsx +0 -0
  220. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.csv +9 -0
  221. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.log +168 -0
  222. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.psydat +0 -0
  223. psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.xlsx +0 -0
  224. psychopy/tests/test_data/.DS_Store +0 -0
  225. psychopy/tests/test_hardware/test_CRS_BitsSharp.py.orig +68 -0
  226. psychopy/tests/test_tools/test_arraytools.py +112 -0
  227. psychopy/tests/test_visual/test_image.py.orig +219 -0
  228. psychopy/tools/arraytools.py +47 -0
  229. psychopy/tools/versionchooser.py +1 -1
  230. psychopy/visual/backends/pygletbackend.py +26 -8
  231. psychopy/visual/basevisual.py.orig +1723 -0
  232. psychopy/visual/form.py.orig +1181 -0
  233. psychopy/visual/text.py.orig +752 -0
  234. psychopy/visual/textbox2/textbox2.py.orig +1315 -0
  235. psychopy/visual/window.py +13 -5
  236. psychopy/visual/windowwarp.py.orig +463 -0
  237. {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/METADATA +9 -9
  238. {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/RECORD +244 -78
  239. {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/WHEEL +1 -1
  240. {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/entry_points.txt +2 -0
  241. psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
  242. psychopy/app/locale/cs_CZ/LC_MESSAGE/messages.mo +0 -0
  243. psychopy/app/locale/da_DK/LC_MESSAGE/messages.mo +0 -0
  244. psychopy/app/locale/de_DE/LC_MESSAGE/messages.mo +0 -0
  245. psychopy/app/locale/el_GR/LC_MESSAGE/messages.mo +0 -0
  246. psychopy/app/locale/en_NZ/LC_MESSAGE/messages.mo +0 -0
  247. psychopy/app/locale/en_US/LC_MESSAGE/messages.mo +0 -0
  248. psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
  249. psychopy/app/locale/es_ES/LC_MESSAGE/messages.mo +0 -0
  250. psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
  251. psychopy/app/locale/et_EE/LC_MESSAGE/messages.mo +0 -0
  252. psychopy/app/locale/fa_IR/LC_MESSAGE/messages.mo +0 -0
  253. psychopy/app/locale/fi_FI/LC_MESSAGE/messages.mo +0 -0
  254. psychopy/app/locale/fr_FR/LC_MESSAGE/messages.mo +0 -0
  255. psychopy/app/locale/he_IL/LC_MESSAGE/messages.mo +0 -0
  256. psychopy/app/locale/hi_IN/LC_MESSAGE/messages.mo +0 -0
  257. psychopy/app/locale/hu_HU/LC_MESSAGE/messages.mo +0 -0
  258. psychopy/app/locale/it_IT/LC_MESSAGE/messages.mo +0 -0
  259. psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
  260. psychopy/app/locale/ko_KR/LC_MESSAGE/messages.mo +0 -0
  261. psychopy/app/locale/ms_MY/LC_MESSAGE/messages.mo +0 -0
  262. psychopy/app/locale/nl_NL/LC_MESSAGE/messages.mo +0 -0
  263. psychopy/app/locale/nn_NO/LC_MESSAGE/messages.mo +0 -0
  264. psychopy/app/locale/pl_PL/LC_MESSAGE/messages.mo +0 -0
  265. psychopy/app/locale/pt_PT/LC_MESSAGE/messages.mo +0 -0
  266. psychopy/app/locale/ro_RO/LC_MESSAGE/messages.mo +0 -0
  267. psychopy/app/locale/ru_RU/LC_MESSAGE/messages.mo +0 -0
  268. psychopy/app/locale/sv_SE/LC_MESSAGE/messages.mo +0 -0
  269. psychopy/app/locale/tr_TR/LC_MESSAGE/messages.mo +0 -0
  270. psychopy/app/locale/zh_CN/LC_MESSAGE/messages.mo +0 -0
  271. psychopy/app/locale/zh_TW/LC_MESSAGE/messages.mo +0 -0
  272. psychopy-2024.2.1.dist-info/licenses/AUTHORS.md +0 -138
  273. /psychopy/{app/locale/ar_001/LC_MESSAGE → demos/builder}/.DS_Store +0 -0
  274. /psychopy/{app/locale/es_ES/LC_MESSAGE → demos/builder/Experiments}/.DS_Store +0 -0
  275. /psychopy/{visual → demos/builder/Tools/gammaCalibration/data}/.DS_Store +0 -0
  276. {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,238 @@
1
+
2
+ """The `ioLab python library
3
+ <http://github.com/ioLab/python-ioLabs>`_ is now defunct and the company
4
+ no longer trades
5
+ """
6
+ <<<<<<< Updated upstream
7
+ # This file can't be named ioLabs.py, otherwise "import ioLabs" doesn't work.
8
+ # And iolabs.py (lowercase) did not solve it either, something is case
9
+ # insensitive somewhere
10
+
11
+ from numpy import ubyte
12
+ from psychopy import core, event, logging
13
+
14
+ try:
15
+ import ioLabs
16
+ from ioLabs import USBBox, REPORT, COMMAND
17
+ except ImportError:
18
+ err = """Failed to import the ioLabs library. If you're using your own
19
+ copy of python (not the Standalone distribution of PsychoPy) then
20
+ try installing it with:
21
+ > pip install ioLabs""".replace(' ', '')
22
+ logging.error(err)
23
+
24
+ from psychopy.constants import PRESSED, RELEASED
25
+ btn2str = {0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7',
26
+ 64: 'voice'}
27
+
28
+ # hack to fake a USBBox on ubuntu during documentation
29
+ import sys
30
+ if 'sphinx' in sys.modules:
31
+ USBBox = object
32
+
33
+ class ButtonBox(USBBox):
34
+ """PsychoPy's interface to ioLabs.USBBox. Voice key completely untested.
35
+
36
+ Original author: Jonathan Roberts
37
+ PsychoPy rewrite: Jeremy Gray, 2013
38
+ """
39
+
40
+ def __init__(self):
41
+ """Class to detect and report
42
+ `ioLab button box <http://www.iolab.co.uk>`_.
43
+
44
+ The ioLabs library needs to be installed. It is included in the
45
+ *Standalone* distributions of PsychoPy as of version 1.62.01.
46
+ Otherwise try "pip install ioLabs"
47
+
48
+ Usage::
49
+
50
+ from psychopy.hardware import iolab
51
+ bbox = iolab.ButtonBox()
52
+
53
+ For examples see the demos menu of the PsychoPy Coder or go to the
54
+ URL above.
55
+
56
+ All times are reported in units of seconds.
57
+ """
58
+ ioLabs.USBBox.__init__(self)
59
+ logging.debug('init iolabs bbox')
60
+ self.events = []
61
+ self.status = None # helps Builder
62
+ self._lastReset = 0.0 # time on baseclock when bbox clock was reset
63
+ self._baseclock = core.Clock() # for basetime, not RT time
64
+ self.resetClock(log=True) # internal clock on the bbox
65
+ msg = 'button box resetClock(log=True) took %.4fs'
66
+ logging.exp(msg % self._baseclock.getTime())
67
+
68
+ self.commands.add_callback(REPORT.KEYDN, self._onKeyDown)
69
+ self.commands.add_callback(REPORT.KEYUP, self._onKeyUp)
70
+ self.commands.add_callback(REPORT.RTCREP, self._onRtcRep)
71
+
72
+ # set up callbacks for key events ("key" = button and or voice key):
73
+ def _onKey(self, report):
74
+ report.rt = report.rtc / 1000.
75
+ report.btn = report.key_code # int
76
+ report.key = btn2str[report.key_code] # str
77
+ self.events.append(report)
78
+
79
+ def _onKeyDown(self, report):
80
+ report.direction = PRESSED
81
+ self._onKey(report)
82
+
83
+ def _onKeyUp(self, report):
84
+ report.direction = RELEASED
85
+ self._onKey(report)
86
+
87
+ def _onRtcRep(self, report):
88
+ # read internal clock without needing a button-press; not working
89
+ report.rt = self.commands.rtcget()['rtc'] / 1000.
90
+
91
+ def __del__(self):
92
+ # does not seem to ever get called
93
+ self.standby()
94
+ for rep in [REPORT.KEYDN, REPORT.KEYUP, REPORT.RTCREP]:
95
+ self.remove_callback(rep)
96
+ ioLabs.USBBox.__del__(self)
97
+
98
+ def standby(self):
99
+ """Disable all buttons and lights.
100
+ """
101
+ self.buttons.enabled = 0x00 # 8 bit pattern 0=disabled 1=enabled
102
+ self.leds.state = 0xFF # leds == port2 == lights, 8 bits 0=on 1=off
103
+ return self
104
+
105
+ def resetClock(self, log=True):
106
+ """Reset the clock on the bbox internal clock, e.g., at the start
107
+ of a trial.
108
+
109
+ ~1ms for me; logging is much faster than the reset
110
+ """
111
+ # better / faster than self.reset_clock() (no wait for report):
112
+ self.commands.resrtc()
113
+ self._lastReset = self._baseclock.getTime()
114
+ if log:
115
+ msg = 'reset bbox internal clock at basetime = %.3f'
116
+ logging.exp(msg % self._lastReset)
117
+
118
+ def _getTime(self, log=False):
119
+ """Return the time on the bbox internal clock, relative to last reset.
120
+
121
+ Status: rtcget() not working
122
+
123
+ `log=True` will log the bbox time and elapsed CPU (python) time.
124
+ """
125
+ bboxTime = self.commands.rtcget()['rtc'] / 1000.
126
+ logging.debug('bbox rtc: %.3f' % bboxTime)
127
+ if log:
128
+ cpuTime = self._baseclock.getTime() - self._lastReset
129
+ logging.debug('cpu time: %.3f' % cpuTime)
130
+
131
+ return bboxTime
132
+
133
+ def getBaseTime(self):
134
+ """Return the time since init (using the CPU clock, not ioLab bbox).
135
+
136
+ Aim is to provide a similar API as for a Cedrus box.
137
+ Could let both clocks run for a long time to assess relative drift.
138
+ """
139
+ return self._baseclock.getTime()
140
+
141
+ def setEnabled(self, buttonList=(0, 1, 2, 3, 4, 5, 6, 7), voice=False):
142
+ """Set a filter to suppress events from non-enabled buttons.
143
+
144
+ The ioLabs bbox filters buttons in hardware; here we just tell it
145
+ what we want:
146
+ None - disable all buttons
147
+ an integer (0..7) - enable a single button
148
+ a list of integers (0..7) - enable all buttons in the list
149
+
150
+ Set voice=True to enable the voiceKey - gets reported as button 64
151
+ """
152
+ allInRange = all([b in range(8) for b in buttonList])
153
+ if not (buttonList is None or allInRange):
154
+ raise ValueError('buttonList needs to be a list of 0..7, or None')
155
+ self.buttons.enabled = _list2bits(buttonList)
156
+ self.int0.enabled = int(voice)
157
+
158
+ def getEnabled(self):
159
+ """Return a list of the buttons that are currently enabled.
160
+ """
161
+ return _bits2list(self.buttons.enabled)
162
+
163
+ def setLights(self, lightList=(0, 1, 2, 3, 4, 5, 6, 7)):
164
+ """Turn on the specified LEDs (None, 0..7, list of 0..7)
165
+ """
166
+ self.leds.state = ~_list2bits(lightList)
167
+
168
+ def waitEvents(self, downOnly=True, timeout=0, escape='escape',
169
+ wait=0.002):
170
+ """Wait for and return the first button press event.
171
+
172
+ Always calls `clearEvents()` first (like PsychoPy keyboard waitKeys).
173
+
174
+ Use `downOnly=False` to include button-release events.
175
+
176
+ `escape` is a list/tuple of keyboard events that, if pressed, will
177
+ interrupt the bbox wait; `waitKeys` will return `None` in that case.
178
+
179
+ `timeout` is the max time to wait in seconds before returning `None`.
180
+ `timeout` of 0 means no time-out (= default).
181
+ """
182
+ self.clearEvents() # e.g., removes UP from previous DOWN
183
+ if timeout > 0:
184
+ c = core.Clock()
185
+ if escape and not type(escape) in [list, tuple]:
186
+ escape = [escape]
187
+ while True:
188
+ if wait:
189
+ core.wait(wait, 0) # throttle CPU; event RTs come from bbox
190
+ evt = self.getEvents(downOnly=downOnly)
191
+ if evt:
192
+ evt = evt[0]
193
+ break
194
+ if escape and event.getKeys(escape) or 0 < timeout < c.getTime():
195
+ return
196
+ return evt
197
+
198
+ def getEvents(self, downOnly=True):
199
+ """Detect and return a list of all events (likely just one); no block.
200
+
201
+ Use `downOnly=False` to include button-release events.
202
+ """
203
+ if downOnly is False:
204
+ raise NotImplementedError()
205
+ self.process_received_reports()
206
+ evts = []
207
+ for evt in self.events:
208
+ if evt.direction == PRESSED or not downOnly:
209
+ evts.append(evt)
210
+ return evts
211
+
212
+ def clearEvents(self):
213
+ """Discard all button / voice key events.
214
+ """
215
+ self.events[:] = []
216
+ self.commands.clear_received_reports()
217
+ logging.debug('bbox clear events')
218
+
219
+
220
+ pow2 = [2**i for i in range(8)]
221
+
222
+
223
+ def _list2bits(arg):
224
+ # return a numpy.ubyte with bits set based on integers 0..7 in arg
225
+ if type(arg) == int and 0 <= arg < 8:
226
+ return ubyte(pow2[arg])
227
+ elif hasattr(arg, '__iter__'):
228
+ return ubyte(sum([pow2[btn] for btn in arg]))
229
+ else: # None
230
+ return ubyte(0)
231
+
232
+ =======
233
+ >>>>>>> Stashed changes
234
+
235
+ raise DeprecationWarning("The ioLab button box is no longer being sold and the library is no"
236
+ "longer supported. This library has been removed from PsychoPy as of"
237
+ "version 2022.1. We would recommend you use an alternative button box"
238
+ "such as the LabHackers MilliKey <https://www.labhackers.com/millikey.html>")
@@ -891,7 +891,7 @@ class DeviceManager:
891
891
  win, text=str(n + 1),
892
892
  size=1, pos=0,
893
893
  alignment="center", anchor="center",
894
- letterHeight=0.5, bold=True,
894
+ letterHeight=0.25, bold=True,
895
895
  fillColor=None, color="white"
896
896
  )
897
897
  lbls.append(lbl)
@@ -155,7 +155,7 @@ class BasePhotodiodeGroup(base.BaseResponseDevice):
155
155
 
156
156
  return channels
157
157
 
158
- def findPhotodiode(self, win, channel=None):
158
+ def findPhotodiode(self, win, channel=None, retryLimit=5):
159
159
  """
160
160
  Draws rectangles on the screen and records photodiode responses to recursively find the location of the diode.
161
161
 
@@ -271,32 +271,46 @@ class BasePhotodiodeGroup(base.BaseResponseDevice):
271
271
  # if none of these have returned, rect is too small to cover the whole photodiode, so return
272
272
  return responsive
273
273
 
274
- # reset state
275
- self.state = [None] * self.channels
276
- self.dispatchMessages()
277
- self.clearResponses()
278
- # recursively shrink rect around the photodiode
279
- responsive = scanQuadrants()
280
- # if cancelled, warn and continue
281
- if responsive is None:
282
- logging.warn(
283
- "`findPhotodiode` procedure cancelled by user."
284
- )
285
- return (
286
- layout.Position(self.pos, units="norm", win=win),
287
- layout.Position(self.size, units="norm", win=win),
288
- )
289
- # if we didn't get any responses at all, prompt to try again
290
- if not responsive:
274
+ def handleNonResponse(label, rect, timeout=5):
275
+ # skip if retry limit hit
276
+ if retryLimit <= 0:
277
+ return None
278
+ # start a countdown
279
+ timer = core.CountdownTimer(start=timeout)
291
280
  # set label text to alert user
292
- label.text = (
281
+ msg = (
293
282
  "Received no responses from photodiode during `findPhotodiode`. Photodiode may not "
294
283
  "be connected or may be configured incorrectly.\n"
295
284
  "\n"
296
- "To continue, use the arrow keys to move the photodiode patch and use the "
297
- "plus/minus keys to resize it.\n"
298
- "\n"
299
- "Press ENTER when finished."
285
+ "To manually specify the photodiode's position, press ENTER. To quit, press "
286
+ "ESCAPE. Otherwise, will retry in {:.0f}s\n"
287
+ )
288
+ label.foreColor = "red"
289
+ # start a frame loop until they press enter
290
+ keys = []
291
+ while timer.getTime() > 0 and not keys:
292
+ # get keys
293
+ keys = kb.getKeys()
294
+ # skip if escape pressed
295
+ if "escape" in keys:
296
+ return None
297
+ # specify manually if return pressed
298
+ if "return" in keys:
299
+ return specifyManually(label=label, rect=rect)
300
+ # format label
301
+ label.text = msg.format(timer.getTime())
302
+ # show label and square
303
+ label.draw()
304
+ # flip
305
+ win.flip()
306
+ # if we timed out, retry whole find procedure
307
+ return self.findPhotodiode(win, channel=channel, retryLimit=retryLimit-1)
308
+
309
+ def specifyManually(label, rect):
310
+ # set label text to alert user
311
+ label.text = (
312
+ "Use the arrow keys to move the photodiode patch and use the plus/minus keys to "
313
+ "resize it. Press ENTER when finished, or press ESCAPE to quit.\n"
300
314
  )
301
315
  label.foreColor = "red"
302
316
  # revert to defaults
@@ -306,12 +320,18 @@ class BasePhotodiodeGroup(base.BaseResponseDevice):
306
320
  # start a frame loop until they press enter
307
321
  keys = []
308
322
  res = 0.05
309
- while "return" not in keys:
323
+ while "return" not in keys and "escape" not in keys:
310
324
  # get keys
311
325
  keys = kb.getKeys()
312
326
  # skip if escape pressed
313
327
  if "escape" in keys:
314
328
  return None
329
+ # finish if return pressed
330
+ if "return" in keys:
331
+ return (
332
+ layout.Position(self.pos, units="norm", win=win),
333
+ layout.Position(self.size, units="norm", win=win),
334
+ )
315
335
  # move rect according to arrow keys
316
336
  pos = list(rect.pos)
317
337
  if "left" in keys:
@@ -335,13 +355,25 @@ class BasePhotodiodeGroup(base.BaseResponseDevice):
335
355
  rect.draw()
336
356
  # flip
337
357
  win.flip()
338
- # wait for a keypress
339
- kb.waitKeys()
340
- # return defaults
358
+
359
+ # reset state
360
+ self.state = [None] * self.channels
361
+ self.dispatchMessages()
362
+ self.clearResponses()
363
+ # recursively shrink rect around the photodiode
364
+ responsive = scanQuadrants()
365
+ # if cancelled, warn and continue
366
+ if responsive is None:
367
+ logging.warn(
368
+ "`findPhotodiode` procedure cancelled by user."
369
+ )
341
370
  return (
342
371
  layout.Position(self.pos, units="norm", win=win),
343
372
  layout.Position(self.size, units="norm", win=win),
344
373
  )
374
+ # if we didn't get any responses at all, prompt to try again
375
+ if not responsive:
376
+ handleNonResponse(label=label, rect=rect)
345
377
  # clear all the events created by this process
346
378
  self.state = [None] * self.channels
347
379
  self.dispatchMessages()
@@ -0,0 +1,51 @@
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-2022 Open Science Tools Ltd.
6
+ # Distributed under the terms of the GNU General Public License (GPL).
7
+
8
+ """To connect to serial ports, e.g. to send/receive trigger pulses
9
+
10
+ This is really just a subclass of the Serial class from the pyserial lib, with
11
+ added functions for the purpose of detecting triggers.
12
+
13
+ Also note that to interact with serial port *devices* with APIs such as
14
+ photometers etc then you might be better using the psychopy.hardware.SerialDevice
15
+ base class.
16
+ """
17
+
18
+ import time
19
+ import serial
20
+
21
+ """
22
+ Note that py serial.Serial has announced deprecating camelCase for
23
+ snake_case as of version 3.0 but not clear when this will actually
24
+ be removed. We're currently sticking with camelCase since that meets
25
+ our own style guide.
26
+ """
27
+
28
+
29
+ class SerialPort(serial.Serial):
30
+ """
31
+ """
32
+ def waitTriggers(self, triggers=None, maxWait=None):
33
+ """Waits for one of the trigger characters to be detected
34
+
35
+ If none of the characters are detected within the maxWait
36
+ then None is returned. Otherwise the value of the detected
37
+ trigger is returned.
38
+
39
+ Params
40
+ ------
41
+
42
+ """
43
+ if type(triggers) in [bytes, str]:
44
+ triggers = {triggers}
45
+ t0 = time.time()
46
+ # can't just use serial port timeout because check for char
47
+ while maxWait is None or (time.time()-t0 < maxWait):
48
+ chars = self.read(self.inWaiting())
49
+ for thisTrigger in triggers:
50
+ if thisTrigger in chars:
51
+ return thisTrigger
@@ -8,7 +8,7 @@ class SpeakerDevice(BaseDevice):
8
8
  profiles = self.getAvailableDevices()
9
9
 
10
10
  # if index is default (-1), setup a default device index
11
- if not isinstance(index, (int, float)) or index < 0:
11
+ if not isinstance(index, (int, float)):
12
12
  index = profiles[0]['index'] # initialize as the first device
13
13
 
14
14
  # check if a default device is already set and update index
@@ -23,8 +23,8 @@ class SpeakerDevice(BaseDevice):
23
23
  if profile['deviceName'] == defaultDevice:
24
24
  index = profile['index']
25
25
 
26
- available_index = [profile['index'] for profile in profiles]
27
- if index < 0 or index not in available_index:
26
+ available_index = [profile['index'] for profile in profiles] + [-1]
27
+ if index not in available_index:
28
28
  logging.error("No speaker device found with index %d" % index)
29
29
 
30
30
  # store index
@@ -86,4 +86,4 @@ class SpeakerDevice(BaseDevice):
86
86
  }
87
87
  devices.append(device)
88
88
 
89
- return devices
89
+ return devices