psychopy 2024.1.4__py3-none-any.whl → 2024.2.0__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 (325) hide show
  1. psychopy/.DS_Store +0 -0
  2. psychopy/CHANGELOG.txt +206 -0
  3. psychopy/GIT_SHA +1 -0
  4. psychopy/VERSION +1 -0
  5. psychopy/__init__.py +77 -15
  6. psychopy/app/Resources/classic/plugin16.png +0 -0
  7. psychopy/app/Resources/classic/plugin16@2x.png +0 -0
  8. psychopy/app/Resources/dark/plugin16.png +0 -0
  9. psychopy/app/Resources/dark/plugin16@2x.png +0 -0
  10. psychopy/app/Resources/light/plugin16.png +0 -0
  11. psychopy/app/Resources/light/plugin16@2x.png +0 -0
  12. psychopy/app/__init__.py +76 -2
  13. psychopy/app/_psychopyApp.py +126 -101
  14. psychopy/app/builder/builder.py +14 -10
  15. psychopy/app/builder/dialogs/__init__.py +8 -8
  16. psychopy/app/builder/dialogs/dlgsConditions.py +12 -13
  17. psychopy/app/builder/dialogs/paramCtrls.py +24 -57
  18. psychopy/app/builder/validators.py +2 -2
  19. psychopy/app/coder/codeEditorBase.py +8 -8
  20. psychopy/app/coder/coder.py +4 -4
  21. psychopy/app/connections/sendusage.py +2 -2
  22. psychopy/app/connections/updates.py +9 -9
  23. psychopy/app/dialogs.py +34 -2
  24. psychopy/app/idle.py +31 -0
  25. psychopy/app/jobs.py +21 -3
  26. psychopy/app/linuxconfig/__init__.py +9 -0
  27. psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
  28. psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +4602 -2540
  29. psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
  30. psychopy/app/locale/es_CO/LC_MESSAGE/messages.po +56 -54
  31. psychopy/app/locale/es_ES/LC_MESSAGE/messages.po +53 -43
  32. psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
  33. psychopy/app/locale/es_US/LC_MESSAGE/messages.po +56 -54
  34. psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
  35. psychopy/app/locale/ja_JP/LC_MESSAGE/messages.po +1011 -942
  36. psychopy/app/locale/pt_PT/LC_MESSAGE/messages.po +9415 -5
  37. psychopy/app/pavlovia_ui/_base.py +33 -3
  38. psychopy/app/pavlovia_ui/search.py +0 -1
  39. psychopy/app/plugin_manager/dialog.py +104 -51
  40. psychopy/app/plugin_manager/packages.py +5 -0
  41. psychopy/app/plugin_manager/plugins.py +145 -67
  42. psychopy/app/preferencesDlg.py +8 -8
  43. psychopy/app/psychopyApp.py +11 -5
  44. psychopy/app/ribbon.py +124 -14
  45. psychopy/app/runner/runner.py +6 -1
  46. psychopy/app/stdout/stdOutRich.py +27 -11
  47. psychopy/app/themes/icons.py +52 -2
  48. psychopy/assets/__init__.py +0 -0
  49. psychopy/assets/click.png +0 -0
  50. psychopy/assets/clicknext.png +0 -0
  51. psychopy/assets/next.png +0 -0
  52. psychopy/assets/psychopy.ico +0 -0
  53. psychopy/assets/psychopy.png +0 -0
  54. psychopy/assets/templates/__init__.py +0 -0
  55. psychopy/assets/touch.png +0 -0
  56. psychopy/assets/touchnext.png +0 -0
  57. psychopy/assets/window.ico +0 -0
  58. psychopy/changes/2023.1.0.md +9 -0
  59. psychopy/changes/2024.1.0.md +16 -0
  60. psychopy/changes/__init__.py +0 -0
  61. psychopy/clock.py +2 -2
  62. psychopy/colors.py +2 -1
  63. psychopy/compatibility.py +53 -1
  64. psychopy/contrib/.DS_Store +0 -0
  65. psychopy/contrib/configobj/__init__.py +10 -8
  66. psychopy/data/__init__.py +3 -2
  67. psychopy/data/base.py +5 -5
  68. psychopy/data/experiment.py +130 -4
  69. psychopy/data/routine.py +56 -0
  70. psychopy/data/staircase.py +2 -2
  71. psychopy/data/trial.py +559 -97
  72. psychopy/data/utils.py +56 -21
  73. psychopy/demos/.DS_Store +0 -0
  74. psychopy/demos/builder/.DS_Store +0 -0
  75. psychopy/demos/builder/Design Templates/.DS_Store +0 -0
  76. psychopy/demos/builder/Experiments/.DS_Store +0 -0
  77. psychopy/demos/builder/Feature Demos/.DS_Store +0 -0
  78. psychopy/demos/builder/Feature Demos/buttonBox/buttonBoxDemo.psyexp +375 -0
  79. psychopy/demos/builder/Feature Demos/buttonBox/readme.md +5 -0
  80. psychopy/demos/builder/Feature Demos/pilotMode/pilotMode.psyexp +433 -0
  81. psychopy/demos/builder/Feature Demos/pilotMode/readme.md +7 -0
  82. psychopy/demos/builder/Hardware/.DS_Store +0 -0
  83. psychopy/demos/builder/Helper Tools/.DS_Store +0 -0
  84. psychopy/demos/coder/.DS_Store +0 -0
  85. psychopy/demos/coder/hardware/testSoundLatency.py +2 -2
  86. psychopy/demos/coder/iohub/.DS_Store +0 -0
  87. psychopy/demos/coder/misc/hdf5_2_csv +33 -0
  88. psychopy/event.py +30 -29
  89. psychopy/experiment/.DS_Store +0 -0
  90. psychopy/experiment/_experiment.py +6 -6
  91. psychopy/experiment/components/.DS_Store +0 -0
  92. psychopy/experiment/components/__init__.py +6 -3
  93. psychopy/experiment/components/_base.py +286 -131
  94. psychopy/experiment/components/aperture/.DS_Store +0 -0
  95. psychopy/experiment/components/brush/.DS_Store +0 -0
  96. psychopy/experiment/components/button/.DS_Store +0 -0
  97. psychopy/experiment/components/button/__init__.py +5 -1
  98. psychopy/experiment/components/buttonBox/.DS_Store +0 -0
  99. psychopy/experiment/components/camera/.DS_Store +0 -0
  100. psychopy/experiment/components/code/.DS_Store +0 -0
  101. psychopy/experiment/components/dots/.DS_Store +0 -0
  102. psychopy/experiment/components/eyetracker_record/.DS_Store +0 -0
  103. psychopy/experiment/components/eyetracker_record/__init__.py +92 -30
  104. psychopy/experiment/components/form/.DS_Store +0 -0
  105. psychopy/experiment/components/form/__init__.py +6 -2
  106. psychopy/experiment/components/grating/.DS_Store +0 -0
  107. psychopy/experiment/components/grating/__init__.py +14 -3
  108. psychopy/experiment/components/image/.DS_Store +0 -0
  109. psychopy/experiment/components/image/__init__.py +14 -3
  110. psychopy/experiment/components/joyButtons/.DS_Store +0 -0
  111. psychopy/experiment/components/joystick/.DS_Store +0 -0
  112. psychopy/experiment/components/keyboard/.DS_Store +0 -0
  113. psychopy/experiment/components/keyboard/__init__.py +22 -10
  114. psychopy/experiment/components/microphone/.DS_Store +0 -0
  115. psychopy/experiment/components/microphone/__init__.py +59 -39
  116. psychopy/experiment/components/mouse/.DS_Store +0 -0
  117. psychopy/experiment/components/mouse/__init__.py +44 -29
  118. psychopy/experiment/components/movie/.DS_Store +0 -0
  119. psychopy/experiment/components/movie/__init__.py +1 -1
  120. psychopy/experiment/components/panorama/.DS_Store +0 -0
  121. psychopy/experiment/components/parallelOut/.DS_Store +0 -0
  122. psychopy/experiment/components/patch/.DS_Store +0 -0
  123. psychopy/experiment/components/polygon/.DS_Store +0 -0
  124. psychopy/experiment/components/polygon/__init__.py +26 -6
  125. psychopy/experiment/components/progress/.DS_Store +0 -0
  126. psychopy/experiment/components/ratingScale/.DS_Store +0 -0
  127. psychopy/experiment/components/resourceManager/.DS_Store +0 -0
  128. psychopy/experiment/components/roi/.DS_Store +0 -0
  129. psychopy/experiment/components/roi/__init__.py +5 -0
  130. psychopy/experiment/components/routineSettings/.DS_Store +0 -0
  131. psychopy/experiment/components/routineSettings/__init__.py +57 -10
  132. psychopy/experiment/components/serialOut/.DS_Store +0 -0
  133. psychopy/experiment/components/settings/.DS_Store +0 -0
  134. psychopy/experiment/components/settings/__init__.py +117 -42
  135. psychopy/experiment/components/slider/.DS_Store +0 -0
  136. psychopy/experiment/components/sound/.DS_Store +0 -0
  137. psychopy/experiment/components/sound/__init__.py +54 -19
  138. psychopy/experiment/components/static/.DS_Store +0 -0
  139. psychopy/experiment/components/static/__init__.py +1 -1
  140. psychopy/experiment/components/text/.DS_Store +0 -0
  141. psychopy/experiment/components/text/__init__.py +28 -3
  142. psychopy/experiment/components/textbox/.DS_Store +0 -0
  143. psychopy/experiment/components/textbox/__init__.py +12 -2
  144. psychopy/experiment/components/unknown/.DS_Store +0 -0
  145. psychopy/experiment/components/unknown/__init__.py +1 -2
  146. psychopy/experiment/components/unknownPlugin/.DS_Store +0 -0
  147. psychopy/experiment/components/unknownPlugin/__init__.py +2 -2
  148. psychopy/experiment/components/variable/.DS_Store +0 -0
  149. psychopy/experiment/flow.py +11 -4
  150. psychopy/experiment/loops.py +85 -37
  151. psychopy/experiment/params.py +74 -32
  152. psychopy/experiment/py2js_transpiler.py +8 -1
  153. psychopy/experiment/routines/.DS_Store +0 -0
  154. psychopy/experiment/routines/_base.py +102 -22
  155. psychopy/experiment/routines/counterbalance/.DS_Store +0 -0
  156. psychopy/experiment/routines/counterbalance/__init__.py +5 -1
  157. psychopy/experiment/routines/eyetracker_calibrate/.DS_Store +0 -0
  158. psychopy/experiment/routines/eyetracker_validate/.DS_Store +0 -0
  159. psychopy/experiment/routines/pavlovia_survey/.DS_Store +0 -0
  160. psychopy/experiment/routines/photodiodeValidator/.DS_Store +0 -0
  161. psychopy/experiment/routines/photodiodeValidator/__init__.py +6 -5
  162. psychopy/experiment/routines/unknown/.DS_Store +0 -0
  163. psychopy/gui/wxgui.py +4 -4
  164. psychopy/hardware/.DS_Store +0 -0
  165. psychopy/hardware/__init__.py +1 -1
  166. psychopy/hardware/base.py +12 -0
  167. psychopy/hardware/camera/__init__.py +1 -15
  168. psychopy/hardware/cedrus.py +10 -11
  169. psychopy/hardware/crs/colorcal.py +13 -22
  170. psychopy/hardware/crs/optical.py +10 -20
  171. psychopy/hardware/emulator.py +17 -14
  172. psychopy/hardware/eyetracker.py +42 -118
  173. psychopy/hardware/gammasci.py +4 -15
  174. psychopy/hardware/keyboard.py +102 -10
  175. psychopy/hardware/listener.py +3 -0
  176. psychopy/hardware/microphone.py +148 -18
  177. psychopy/hardware/minolta.py +8 -15
  178. psychopy/hardware/photodiode.py +191 -16
  179. psychopy/hardware/photometer/__init__.py +11 -19
  180. psychopy/hardware/pr.py +8 -15
  181. psychopy/hardware/speaker.py +39 -4
  182. psychopy/info.py +0 -71
  183. psychopy/iohub/.DS_Store +0 -0
  184. psychopy/iohub/__init__.py +1 -1
  185. psychopy/iohub/client/__init__.py +30 -20
  186. psychopy/iohub/client/keyboard.py +24 -24
  187. psychopy/iohub/datastore/__init__.py +2 -2
  188. psychopy/iohub/datastore/util.py +2 -2
  189. psychopy/iohub/default_config.yaml +1 -1
  190. psychopy/iohub/devices/.DS_Store +0 -0
  191. psychopy/iohub/devices/__init__.py +112 -25
  192. psychopy/iohub/devices/deviceConfigValidation.py +2 -1
  193. psychopy/iohub/devices/experiment/default_experiment.yaml +12 -1
  194. psychopy/iohub/devices/experiment/supported_config_settings.yaml +5 -1
  195. psychopy/iohub/devices/eyetracker/.DS_Store +0 -0
  196. psychopy/iohub/devices/eyetracker/__init__.py +46 -0
  197. psychopy/iohub/devices/eyetracker/calibration/procedure.py +2 -2
  198. psychopy/iohub/devices/eyetracker/hw/gazepoint/__init__.py +14 -2
  199. psychopy/iohub/devices/eyetracker/hw/mouse/eyetracker.py +3 -4
  200. psychopy/iohub/server.py +2 -2
  201. psychopy/iohub/start_iohub_process.py +3 -0
  202. psychopy/iohub/util/__init__.py +62 -70
  203. psychopy/layout.py +5 -5
  204. psychopy/logging.py +8 -1
  205. psychopy/microphone.py +10 -37
  206. psychopy/platform_specific/__init__.py +0 -2
  207. psychopy/platform_specific/darwin.py +1 -3
  208. psychopy/platform_specific/linux.py +31 -33
  209. psychopy/platform_specific/win32.py +38 -13
  210. psychopy/plugins/__init__.py +148 -116
  211. psychopy/plugins/util.py +39 -0
  212. psychopy/preferences/Darwin.spec +4 -2
  213. psychopy/preferences/FreeBSD.spec +4 -2
  214. psychopy/preferences/Linux.spec +4 -2
  215. psychopy/preferences/Windows.spec +4 -2
  216. psychopy/preferences/baseNoArch.spec +4 -2
  217. psychopy/preferences/preferences.py +47 -24
  218. psychopy/projects/pavlovia.py +47 -4
  219. psychopy/scripts/psyexpCompile.py +0 -4
  220. psychopy/session.py +153 -21
  221. psychopy/sound/__init__.py +31 -21
  222. psychopy/sound/_base.py +20 -3
  223. psychopy/sound/audioclip.py +320 -33
  224. psychopy/sound/backend_ptb.py +47 -58
  225. psychopy/sound/backend_pygame.py +1 -1
  226. psychopy/sound/backend_pysound.py +6 -15
  227. psychopy/sound/transcribe.py +53 -0
  228. psychopy/tests/.DS_Store +0 -0
  229. psychopy/tests/data/.DS_Store +0 -0
  230. psychopy/tests/data/TestUnknownPluginComponent_load_resave.psyexp +135 -0
  231. psychopy/tests/data/Test_textbox/test_ori_0_bottom right.png +0 -0
  232. psychopy/tests/data/Test_textbox/test_ori_0_center.png +0 -0
  233. psychopy/tests/data/Test_textbox/test_ori_0_top left.png +0 -0
  234. psychopy/tests/data/Test_textbox/test_ori_120_bottom right.png +0 -0
  235. psychopy/tests/data/Test_textbox/test_ori_120_center.png +0 -0
  236. psychopy/tests/data/Test_textbox/test_ori_120_top left.png +0 -0
  237. psychopy/tests/data/Test_textbox/test_ori_180_bottom right.png +0 -0
  238. psychopy/tests/data/Test_textbox/test_ori_180_center.png +0 -0
  239. psychopy/tests/data/Test_textbox/test_ori_180_top left.png +0 -0
  240. psychopy/tests/data/Test_textbox/test_ori_240_bottom right.png +0 -0
  241. psychopy/tests/data/Test_textbox/test_ori_240_center.png +0 -0
  242. psychopy/tests/data/Test_textbox/test_ori_240_top left.png +0 -0
  243. psychopy/tests/data/correctScript/.DS_Store +0 -0
  244. psychopy/tests/data/test_components/testClearKeyboard/testClearKeyboard.psyexp +200 -0
  245. psychopy/tests/data/test_session/.DS_Store +0 -0
  246. psychopy/tests/data/test_session/root/testFutureTrials/testFutureTrials.psyexp +155 -0
  247. psychopy/tests/data/test_session/root/testTrialNav/trialNav.psyexp +158 -0
  248. psychopy/tests/test_app/.DS_Store +0 -0
  249. psychopy/tests/test_app/conftest.py +2 -2
  250. psychopy/tests/test_app/test_speed.py +4 -1
  251. psychopy/tests/test_data/test_TrialHandler2.py +146 -1
  252. psychopy/tests/test_experiment/.DS_Store +0 -0
  253. psychopy/tests/test_experiment/needs_wx/genComponsTemplate.py +3 -3
  254. psychopy/tests/test_experiment/needs_wx/test_components.py +2 -2
  255. psychopy/tests/test_experiment/test_components/test_KeyboardComponent.py +28 -0
  256. psychopy/tests/test_experiment/test_components/test_UnknownPluginComponent.py +27 -0
  257. psychopy/tests/test_experiment/test_components/test_base_components.py +58 -0
  258. psychopy/tests/test_experiment/test_py2js.py +1 -1
  259. psychopy/tests/test_hardware/test_keyboard.py +31 -0
  260. psychopy/tests/test_hardware/test_ports.py +1 -11
  261. psychopy/tests/test_liaison/test_Liaison.py +47 -0
  262. psychopy/tests/test_misc/test_core.py +5 -0
  263. psychopy/tests/test_session/test_Session.py +5 -1
  264. psychopy/tests/test_tools/test_versionchooser.py +39 -8
  265. psychopy/tests/test_visual/test_all_stimuli.py +0 -97
  266. psychopy/tests/test_visual/test_image.py +6 -5
  267. psychopy/tests/test_visual/test_textbox.py +36 -0
  268. psychopy/tests/utils.py +4 -0
  269. psychopy/tools/filetools.py +1 -1
  270. psychopy/tools/pkgtools.py +160 -137
  271. psychopy/tools/versionchooser.py +10 -10
  272. psychopy/tools/wizard.py +3 -3
  273. psychopy/visual/.DS_Store +0 -0
  274. psychopy/visual/backends/pygletbackend.py +24 -13
  275. psychopy/visual/basevisual.py +5 -11
  276. psychopy/visual/button.py +2 -14
  277. psychopy/visual/helpers.py +5 -5
  278. psychopy/visual/line.py +1 -2
  279. psychopy/visual/movie2.py +7 -816
  280. psychopy/visual/movie3.py +7 -589
  281. psychopy/visual/movies/__init__.py +8 -11
  282. psychopy/visual/movies/frame.py +5 -2
  283. psychopy/visual/movies/players/ffpyplayer_player.py +5 -2
  284. psychopy/visual/noise.py +8 -7
  285. psychopy/visual/patch.py +7 -16
  286. psychopy/visual/radial.py +9 -7
  287. psychopy/visual/ratingscale.py +8 -1415
  288. psychopy/visual/secondorder.py +10 -9
  289. psychopy/visual/shape.py +7 -2
  290. psychopy/visual/text.py +1 -1
  291. psychopy/visual/textbox2/textbox2.py +28 -5
  292. {psychopy-2024.1.4.dist-info → psychopy-2024.2.0.dist-info}/METADATA +8 -13
  293. {psychopy-2024.1.4.dist-info → psychopy-2024.2.0.dist-info}/RECORD +307 -213
  294. {psychopy-2024.1.4.dist-info → psychopy-2024.2.0.dist-info}/WHEEL +1 -1
  295. psychopy/app/Resources/click.png +0 -0
  296. psychopy/app/Resources/next.png +0 -0
  297. psychopy/experiment/components/patch/__init__.py +0 -121
  298. psychopy/experiment/components/patch/classic/patch.png +0 -0
  299. psychopy/experiment/components/patch/dark/patch.png +0 -0
  300. psychopy/experiment/components/patch/dark/patch@2x.png +0 -0
  301. psychopy/experiment/components/patch/light/patch.png +0 -0
  302. psychopy/experiment/components/patch/light/patch@2x.png +0 -0
  303. psychopy/experiment/components/ratingScale/__init__.py +0 -337
  304. psychopy/experiment/components/ratingScale/classic/ratingscale.png +0 -0
  305. psychopy/experiment/components/ratingScale/classic/ratingscale@2x.png +0 -0
  306. psychopy/experiment/components/ratingScale/dark/ratingScale@2x.png +0 -0
  307. psychopy/experiment/components/ratingScale/dark/ratingscale.png +0 -0
  308. psychopy/experiment/components/ratingScale/light/ratingScale@2x.png +0 -0
  309. psychopy/experiment/components/ratingScale/light/ratingscale.png +0 -0
  310. psychopy/platform_specific/posix.py +0 -16
  311. psychopy/tests/test_sound/test_microphone.py +0 -217
  312. psychopy/tests/test_visual/test_ratingScale.py +0 -299
  313. /psychopy/{app/Resources → assets}/Psychopy Window Favicon@16w.png +0 -0
  314. /psychopy/{app/Resources → assets}/Psychopy Window Favicon@32w.png +0 -0
  315. /psychopy/{app/Resources → assets}/USB-C.png +0 -0
  316. /psychopy/{app/Resources → assets}/USB.png +0 -0
  317. /psychopy/{app/Resources → assets}/creditCard.png +0 -0
  318. /psychopy/{app/Resources → assets}/default.mp3 +0 -0
  319. /psychopy/{app/Resources → assets}/default.mp4 +0 -0
  320. /psychopy/{app/Resources → assets}/default.png +0 -0
  321. /psychopy/{app/Resources → assets/templates}/instruct1.png +0 -0
  322. /psychopy/{app/Resources → assets/templates}/instruct2.png +0 -0
  323. {psychopy-2024.1.4.dist-info → psychopy-2024.2.0.dist-info}/entry_points.txt +0 -0
  324. {psychopy-2024.1.4.dist-info → psychopy-2024.2.0.dist-info}/licenses/AUTHORS.md +0 -0
  325. {psychopy-2024.1.4.dist-info → psychopy-2024.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -29,18 +29,27 @@ if not importCtypesFailed:
29
29
  class _SchedParams(ctypes.Structure):
30
30
  _fields_ = [('sched_priority', ctypes.c_int)]
31
31
 
32
- warnMax = """Could not raise thread priority with sched_setscheduler.
32
+ # Text that appears at the top of the dialog with provides instructions to the
33
+ # user.
34
+ _introStr = (
35
+ u"Could not set the thread priority with sched_setscheduler.\n"
36
+ u"For optimal performance on Linux, Psychtoolbox requires additional\n"
37
+ u"configuration changes to be made to this system by entering the\n"
38
+ u"following commands into your terminal:\n\n{cmdstr}"
39
+ )
33
40
 
34
- To enable rush(), if you are using a debian-based Linux, try this:
35
- 'sudo setcap cap_sys_nice=eip %s' [NB: install 'setcap' first.]
36
- If you are using the system's python (eg /usr/bin/python2.x), its highly
37
- recommended to change cap_sys_nice back to normal afterwards:
38
- 'sudo setcap cap_sys_nice= %s'"""
39
-
40
- warnNormal = ("Failed to set thread priority to normal with "
41
- "sched_setscheduler.\n"
42
- "Try: 'sudo setcap cap_sys_nice= %s'")
41
+ # config file path
42
+ _confPath = u"/etc/security/limits.d/99-psychopylimits.conf"
43
43
 
44
+ # these are the commands we want the user to run in their terminal
45
+ _cmdStr = (
46
+ u"sudo groupadd --force psychopy\n\n"
47
+ u"sudo usermod -a -G psychopy $USER\n\n"
48
+ u"sudo gedit {fpath}\n"
49
+ u"@psychopy - nice -20\n"
50
+ u"@psychopy - rtprio 50\n"
51
+ u"@psychopy - memlock unlimited")
52
+ warnMax = _introStr.format(cmdstr=_cmdStr.format(fpath=_confPath))
44
53
 
45
54
  def rush(value=True, realtime=False):
46
55
  """Raise the priority of the current thread/process using
@@ -48,32 +57,21 @@ def rush(value=True, realtime=False):
48
57
 
49
58
  realtime arg is not used in Linux implementation.
50
59
 
51
- NB for rush() to work on (debian-based?) Linux requires that the
52
- script is run using a copy of python that is allowed to change
53
- priority, eg: sudo setcap cap_sys_nice=eip <sys.executable>,
54
- and maybe restart PsychoPy. If <sys.executable> is the system python,
55
- it's important to restore it back to normal to avoid possible
56
- side-effects. Alternatively, use a different python executable,
57
- and change its cap_sys_nice.
60
+ NB for rush() to work on Linux requires that the script is run by
61
+ a user with sufficient permissions to raise the priority of a process.
62
+ In PsychoPy, we suggest adding the user to a group with these permissions.
58
63
 
59
- For RedHat-based systems, 'sudo chrt ...' at run-time might be
60
- needed instead, not sure.
61
- see http://rt.et.redhat.com/wiki/images/8/8e/Rtprio.pdf
64
+ If this function returns `False`, see the log for instructions on how
65
+ to set up such a group.
62
66
  """
63
67
  if importCtypesFailed:
64
68
  return False
65
69
 
66
- if value: # set to RR with max priority
67
- schedParams = _SchedParams()
68
- schedParams.sched_priority = c.sched_get_priority_max(SCHED_RR)
69
- err = c.sched_setscheduler(0, SCHED_RR, ctypes.byref(schedParams))
70
- if err == -1: # returns 0 if OK
71
- logging.warning(warnMax % (sys.executable, sys.executable))
72
- else: # set to RR with normal priority
73
- schedParams = _SchedParams()
74
- schedParams.sched_priority = c.sched_get_priority_min(SCHED_NORMAL)
75
- err = c.sched_setscheduler(0, SCHED_NORMAL, ctypes.byref(schedParams))
76
- if err == -1: # returns 0 if OK
77
- logging.warning(warnNormal % sys.executable)
70
+ schedParams = _SchedParams()
71
+ sched = SCHED_RR if value else SCHED_NORMAL
72
+ schedParams.sched_priority = c.sched_get_priority_min(sched)
73
+ err = c.sched_setscheduler(0, sched, ctypes.byref(schedParams))
74
+ if err == -1:
75
+ logging.warning(warnMax)
78
76
 
79
- return True
77
+ return not err
@@ -18,10 +18,9 @@
18
18
  # define THREAD_PRIORITY_HIGHEST 2
19
19
  # define THREAD_PRIORITY_TIME_CRITICAL 15
20
20
 
21
- import os
22
-
23
21
  try:
24
22
  from ctypes import windll
23
+ from ctypes.wintypes import HANDLE, DWORD, BOOL, INT, UINT
25
24
  windll = windll.kernel32
26
25
  importWindllFailed = False
27
26
  except Exception:
@@ -47,6 +46,28 @@ ES_CONTINUOUS = 0x80000000
47
46
  ES_DISPLAY_REQUIRED = 0x00000002
48
47
  ES_SYSTEM_REQUIRED = 0x00000001
49
48
 
49
+ GetCurrentProcessId = windll.GetCurrentProcessId
50
+ GetCurrentProcessId.restype = HANDLE
51
+
52
+ OpenProcess = windll.OpenProcess
53
+ OpenProcess.restype = HANDLE
54
+ OpenProcess.argtypes = (DWORD, BOOL, DWORD)
55
+
56
+ GetCurrentThread = windll.GetCurrentThread
57
+ GetCurrentThread.restype = HANDLE
58
+
59
+ SetPriorityClass = windll.SetPriorityClass
60
+ SetPriorityClass.restype = BOOL
61
+ SetPriorityClass.argtypes = (HANDLE, DWORD)
62
+
63
+ SetThreadPriority = windll.SetThreadPriority
64
+ SetThreadPriority.restype = BOOL
65
+ SetThreadPriority.argtypes = (HANDLE, INT)
66
+
67
+ SetThreadExecutionState = windll.SetThreadExecutionState
68
+ SetThreadExecutionState.restype = UINT
69
+ SetThreadExecutionState.argtypes = (UINT,)
70
+
50
71
 
51
72
  def rush(enable=True, realtime=False):
52
73
  """Raise the priority of the current thread/process.
@@ -62,21 +83,25 @@ def rush(enable=True, realtime=False):
62
83
  return False
63
84
 
64
85
  pr_rights = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION
65
- pr = windll.OpenProcess(pr_rights, FALSE, os.getpid())
86
+ pr = windll.OpenProcess(pr_rights, FALSE, GetCurrentProcessId())
66
87
  thr = windll.GetCurrentThread()
67
88
 
68
- if enable is True:
69
- if realtime is False:
70
- windll.SetPriorityClass(pr, HIGH_PRIORITY_CLASS)
71
- windll.SetThreadPriority(thr, THREAD_PRIORITY_HIGHEST)
89
+ # In this context, non-zero is success and zero is error
90
+ out = 1
91
+
92
+ if enable:
93
+ if not realtime:
94
+ out = SetPriorityClass(pr, HIGH_PRIORITY_CLASS) != 0
95
+ out &= SetThreadPriority(thr, THREAD_PRIORITY_HIGHEST) != 0
72
96
  else:
73
- windll.SetPriorityClass(pr, REALTIME_PRIORITY_CLASS)
74
- windll.SetThreadPriority(thr, THREAD_PRIORITY_TIME_CRITICAL)
97
+ out = SetPriorityClass(pr, REALTIME_PRIORITY_CLASS) != 0
98
+ out &= SetThreadPriority(thr, THREAD_PRIORITY_TIME_CRITICAL) != 0
75
99
 
76
100
  else:
77
- windll.SetPriorityClass(pr, NORMAL_PRIORITY_CLASS)
78
- windll.SetThreadPriority(thr, THREAD_PRIORITY_NORMAL)
79
- return True
101
+ out = SetPriorityClass(pr, NORMAL_PRIORITY_CLASS) != 0
102
+ out &= SetThreadPriority(thr, THREAD_PRIORITY_NORMAL) != 0
103
+
104
+ return out != 0
80
105
 
81
106
 
82
107
  def waitForVBL():
@@ -95,5 +120,5 @@ def sendStayAwake():
95
120
  Currently supported on: windows, macOS.
96
121
  """
97
122
  code = ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED
98
- success = windll.SetThreadExecutionState(code)
123
+ success = SetThreadExecutionState(code)
99
124
  return success
@@ -29,20 +29,19 @@ import sys
29
29
  import inspect
30
30
  import collections
31
31
  import hashlib
32
- import importlib
33
- import psychopy.tools.pkgtools as pkgtools
34
- import pkg_resources
35
- import psychopy.tools.pkgtools as pkgtools
32
+ import importlib, importlib.metadata
36
33
  from psychopy import logging
37
34
  from psychopy.preferences import prefs
38
35
 
39
- # add the plugins folder to as a distribution location
40
- try:
41
- pkgtools.addDistribution(prefs.paths['packages'])
42
- except KeyError:
43
- # this error likely wont happen unless the prefs are missing keys
44
- logging.error('Cannot add plugin directory as distribution location. '
45
- 'Plugins will be unavailable this session.')
36
+ # Configure the environment to use our custom site-packages location for
37
+ # user-installed packages (i.e. plugins).
38
+ USER_PACKAGES_PATH = str(prefs.paths['userPackages'])
39
+ # check if we're in a virtual environment or not
40
+ inVenv = hasattr(sys, 'real_prefix') or sys.prefix != sys.base_prefix
41
+
42
+ # add the plugins folder to the path
43
+ if not inVenv and USER_PACKAGES_PATH not in sys.path:
44
+ sys.path.insert(0, USER_PACKAGES_PATH) # add to path
46
45
 
47
46
  # Keep track of plugins that have been loaded. Keys are plugin names and values
48
47
  # are their entry point mappings.
@@ -61,6 +60,40 @@ _failed_plugins_ = []
61
60
  # Functions
62
61
  #
63
62
 
63
+ def getEntryPointGroup(group, subgroups=False):
64
+ """
65
+ Get all entry points which target a specific group.
66
+
67
+ Parameters
68
+ ----------
69
+ group : str
70
+ Group to look for (e.g. "psychopy.experiment.components" for plugin Components)
71
+ subgroups : bool
72
+ If True, then will also look for subgroups (e.g. "psychopy.experiment" will also return
73
+ entry points for "psychopy.experiment.components")
74
+
75
+ Returns
76
+ -------
77
+ list[importlib.metadata.Entrypoint]
78
+ List of EntryPoint objects for the given group
79
+ """
80
+ # start off with no entry points or sections
81
+ entryPoints = []
82
+
83
+ if subgroups:
84
+ # if searching subgroups, iterate through entry point groups
85
+ for thisGroup, eps in importlib.metadata.entry_points().items():
86
+ # get entry points within matching group
87
+ if thisGroup.startswith(group):
88
+ # add to list of all entry points
89
+ entryPoints += eps
90
+ else:
91
+ # otherwise, just get the requested group
92
+ entryPoints += importlib.metadata.entry_points().get(group, [])
93
+
94
+ return entryPoints
95
+
96
+
64
97
  def resolveObjectFromName(name, basename=None, resolve=True, error=True):
65
98
  """Get an object within a module's namespace using a fully-qualified or
66
99
  relative dotted name.
@@ -254,7 +287,7 @@ def getBundleInstallTarget(projectName):
254
287
 
255
288
  """
256
289
  return os.path.join(
257
- prefs.paths['packages'], pkg_resources.safe_name(projectName))
290
+ prefs.paths['packages'], projectName)
258
291
 
259
292
 
260
293
  def refreshBundlePaths():
@@ -285,12 +318,18 @@ def refreshBundlePaths():
285
318
  pluginTopLevelDirs = os.listdir(pluginBaseDir)
286
319
  for pluginDir in pluginTopLevelDirs:
287
320
  fullPath = os.path.join(pluginBaseDir, pluginDir)
288
- allDists = pkg_resources.find_distributions(fullPath, only=False)
321
+ allDists = importlib.metadata.distributions(path=pluginDir)
289
322
  if not allDists: # no packages found, move on
290
323
  continue
291
324
 
292
325
  # does the sud-directory contain an appropriately named distribution?
293
- validDist = any([dist.project_name == pluginDir for dist in allDists])
326
+ validDist = False
327
+ for dist in allDists:
328
+ if sys.version.startswith("3.8"):
329
+ distName = dist.metadata['name']
330
+ else:
331
+ distName = dist.name
332
+ validDist = validDist or distName == pluginDir
294
333
  if not validDist:
295
334
  continue
296
335
 
@@ -301,11 +340,41 @@ def refreshBundlePaths():
301
340
  foundBundles.append(pluginDir)
302
341
 
303
342
  # refresh package index since the working set is now stale
304
- pkgtools.refreshPackages()
343
+ scanPlugins()
305
344
 
306
345
  return foundBundles
307
346
 
308
347
 
348
+ def getPluginConfigPath(plugin):
349
+ """Get the path to the configuration file for a plugin.
350
+
351
+ This function returns the path to folder alloted to a plugin for storing
352
+ configuration files. This is useful for plugins that require user settings
353
+ to be stored in a file.
354
+
355
+ Parameters
356
+ ----------
357
+ plugin : str
358
+ Name of the plugin package to get the configuration file for.
359
+
360
+ Returns
361
+ -------
362
+ str
363
+ Path to the configuration file for the plugin.
364
+
365
+ """
366
+ # check if the plugin is installed first
367
+ if plugin not in _installed_plugins_:
368
+ raise ValueError("Plugin `{}` is not installed.".format(plugin))
369
+
370
+ # get the config directory
371
+ import pathlib
372
+ configDir = pathlib.Path(prefs.paths['configs']) / 'plugins' / plugin
373
+ configDir.mkdir(parents=True, exist_ok=True)
374
+
375
+ return configDir
376
+
377
+
309
378
  def installPlugin(package, local=True, upgrade=False, forceReinstall=False,
310
379
  noDeps=False):
311
380
  """Install a plugin package.
@@ -327,7 +396,8 @@ def installPlugin(package, local=True, upgrade=False, forceReinstall=False,
327
396
 
328
397
  """
329
398
  # determine where to install the package
330
- installWhere = getBundleInstallTarget(package) if local else None
399
+ installWhere = USER_PACKAGES_PATH if local else None
400
+ import psychopy.tools.pkgtools as pkgtools
331
401
  pkgtools.installPackage(
332
402
  package,
333
403
  target=installWhere,
@@ -354,30 +424,27 @@ def scanPlugins():
354
424
 
355
425
  """
356
426
  global _installed_plugins_
357
- _installed_plugins_ = {} # clear installed plugins
358
-
359
- refreshBundlePaths() # refresh plugin bundles directory
360
-
361
- # make sure we have the plugin directory in the working set
362
- pluginDir = prefs.paths['packages']
363
- if pluginDir not in pkg_resources.working_set.entries:
364
- pkg_resources.working_set.add_entry(pluginDir)
365
-
366
- # find all packages with entry points defined
367
- pluginEnv = pkg_resources.Environment() # supported by the platform
368
- dists, _ = pkg_resources.working_set.find_plugins(pluginEnv)
369
-
370
- for dist in dists:
371
- entryMap = dist.get_entry_map()
372
- if any([i.startswith('psychopy') for i in entryMap.keys()]):
373
- logging.debug('Found plugin `{}` at location `{}`.'.format(
374
- dist.project_name, dist.location))
375
- _installed_plugins_[dist.project_name] = entryMap
376
-
377
- # try adding the plugin to the working set
378
- if dist.location not in pkg_resources.working_set.entries:
379
- pkg_resources.working_set.add(dist)
380
-
427
+ _installed_plugins_ = {} # clear the cache
428
+ # iterate through installed packages
429
+ for dist in importlib.metadata.distributions(path=sys.path + [USER_PACKAGES_PATH]):
430
+ # map all entry points
431
+ for ep in dist.entry_points:
432
+ # skip entry points which don't target PsychoPy
433
+ if not ep.group.startswith("psychopy"):
434
+ continue
435
+ # make sure we have an entry for this distribution
436
+ if sys.version.startswith("3.8"):
437
+ distName = dist.metadata['name']
438
+ else:
439
+ distName = dist.name
440
+ if distName not in _installed_plugins_:
441
+ _installed_plugins_[distName] = {}
442
+ # make sure we have an entry for this group
443
+ if ep.group not in _installed_plugins_[distName]:
444
+ _installed_plugins_[distName][ep.group] = {}
445
+ # map entry point
446
+ _installed_plugins_[distName][ep.group][ep.name] = ep
447
+
381
448
  return len(_installed_plugins_)
382
449
 
383
450
 
@@ -507,51 +574,6 @@ def isStartUpPlugin(plugin):
507
574
  return plugin in listPlugins(which='startup')
508
575
 
509
576
 
510
- def loadPluginBuilderElements(plugin):
511
- """
512
- Load entry points from plugin which are relevant to Builder, e.g.
513
- Component/Routine extensions for listing available hardware backends.
514
-
515
- Parameters
516
- ----------
517
- plugin : str
518
- Name of the plugin package to load. This usually refers to the package
519
- or project name.
520
-
521
- Returns
522
- -------
523
- bool
524
- `True` if successful, `False` if failed.
525
- """
526
- # if plugin has already failed to load once, don't try again
527
- if plugin in _failed_plugins_:
528
- return False
529
- # get entry points for plugin
530
- ep = pluginEntryPoints(plugin)
531
- # define modules in which entry points are relevant to Builder
532
- modules = (
533
- "psychopy.experiment.routines",
534
- "psychopy.experiment.components",
535
- )
536
- # get any points pointing to these modules
537
- relevantPoints = []
538
- for mod in modules:
539
- pts = ep.get(mod, {})
540
- relevantPoints += list(pts.values())
541
- # import all relevant classes
542
- for point in relevantPoints:
543
- try:
544
- importlib.import_module(point.module_name)
545
- return True
546
- except:
547
- # if import failed for any reason, log error and mark failure
548
- logging.error(
549
- f"Failed to load {point.module_name}.{point.name} from plugin {plugin}."
550
- )
551
- _failed_plugins_.append(plugin)
552
- return False
553
-
554
-
555
577
  def loadPlugin(plugin):
556
578
  """Load a plugin to extend PsychoPy.
557
579
 
@@ -576,10 +598,11 @@ def loadPlugin(plugin):
576
598
  will continue running. This may be undesirable in some cases, since features
577
599
  the plugin provides may be needed at some point and would lead to undefined
578
600
  behavior if not present. If you want to halt the application if a plugin
579
- fails to load, consider using :func:`requirePlugin`.
601
+ fails to load, consider using :func:`requirePlugin` to assert that a plugin
602
+ is loaded before continuing.
580
603
 
581
604
  It is advised that you use this function only when using PsychoPy as a
582
- library. If using the builder or coder GUI, it is recommended that you use
605
+ library. If using the Builder or Coder GUI, it is recommended that you use
583
606
  the plugin dialog to enable plugins for PsychoPy sessions spawned by the
584
607
  experiment runner. However, you can still use this function if you want to
585
608
  load additional plugins for a given experiment, having their effects
@@ -694,26 +717,43 @@ def loadPlugin(plugin):
694
717
  # that the entry points are valid. This prevents plugins from being
695
718
  # partially loaded which can cause all sorts of undefined behaviour.
696
719
  for attr, ep in attrs.items():
720
+ try:
721
+ # parse the module name from the entry point value
722
+ if ':' in ep.value:
723
+ module_name, _ = ep.value.split(':', 1)
724
+ else:
725
+ module_name = ep.value
726
+ module_name = module_name.split(".")[0]
727
+ except ValueError:
728
+ logging.error(
729
+ "Plugin `{}` entry point `{}` is not formatted correctly. "
730
+ "Skipping.".format(plugin, ep))
731
+
732
+ if plugin not in _failed_plugins_:
733
+ _failed_plugins_.append(plugin)
734
+
735
+ return False
736
+
697
737
  # Load the module the entry point belongs to, this happens
698
738
  # anyways when .load() is called, but we get to access it before
699
739
  # we start binding. If the module has already been loaded, don't
700
740
  # do this again.
701
- if ep.module_name not in sys.modules:
741
+ if module_name not in sys.modules:
702
742
  # Do stuff before loading entry points here, any executable code
703
743
  # in the module will run to configure it.
704
744
  try:
705
- imp = importlib.import_module(ep.module_name)
745
+ imp = importlib.import_module(module_name)
706
746
  except (ModuleNotFoundError, ImportError):
707
747
  importSuccess = False
708
748
  logging.error(
709
749
  "Plugin `{}` entry point requires module `{}`, but it "
710
- "cannot be imported.".format(plugin, ep.module_name))
750
+ "cannot be imported.".format(plugin, module_name))
711
751
  except:
712
752
  importSuccess = False
713
753
  logging.error(
714
754
  "Plugin `{}` entry point requires module `{}`, but an "
715
755
  "error occurred while loading it.".format(
716
- plugin, ep.module_name))
756
+ plugin, module_name))
717
757
  else:
718
758
  importSuccess = True
719
759
 
@@ -742,6 +782,13 @@ def loadPlugin(plugin):
742
782
  # return False
743
783
  try:
744
784
  ep = ep.load() # load the entry point
785
+
786
+ # Raise a warning if the plugin is being loaded from a zip file.
787
+ if '.zip' in inspect.getfile(ep):
788
+ logging.warning(
789
+ "Plugin `{}` is being loaded from a zip file. This may "
790
+ "cause issues with the plugin's functionality.".format(plugin))
791
+
745
792
  except ImportError as e:
746
793
  logging.error(
747
794
  "Failed to load entry point `{}` of plugin `{}`. "
@@ -751,21 +798,11 @@ def loadPlugin(plugin):
751
798
  if plugin not in _failed_plugins_:
752
799
  _failed_plugins_.append(plugin)
753
800
 
754
- return False
755
- except pkg_resources.DistributionNotFound:
756
- logging.error(
757
- "Failed to load entry point `{}` of plugin `{}` due to "
758
- "missing distribution required by the application."
759
- "Skipping.".format(str(ep), plugin))
760
-
761
- if plugin not in _failed_plugins_:
762
- _failed_plugins_.append(plugin)
763
-
764
801
  return False
765
802
  except Exception: # catch everything else
766
803
  logging.error(
767
804
  "Failed to load entry point `{}` of plugin `{}` for unknown"
768
- "reasons. Skipping.".format(str(ep), plugin))
805
+ " reasons. Skipping.".format(str(ep), plugin))
769
806
 
770
807
  if plugin not in _failed_plugins_:
771
808
  _failed_plugins_.append(plugin)
@@ -784,10 +821,16 @@ def loadPlugin(plugin):
784
821
  # add the object to the module or unbound class
785
822
  setattr(targObj, attr, ep)
786
823
  logging.debug(
787
- "Assigning to entry point `{}` to `{}`.".format(
824
+ "Assigning the entry point `{}` to `{}`.".format(
788
825
  ep.__name__, fqn + '.' + attr))
789
826
 
790
827
  # --- handle special cases ---
828
+ # Note - We're going to handle special cases here for now, but
829
+ # this will eventually be handled by special functions in the
830
+ # target modules (e.g. `getAllPhotometers()` in
831
+ # `psychopy.hardware.photometer`) which can detect the loaded
832
+ # attribute inside the module and add it to a collection.
833
+
791
834
  if fqn == 'psychopy.visual.backends': # if window backend
792
835
  _registerWindowBackend(attr, ep)
793
836
  elif fqn == 'psychopy.experiment.components': # if component
@@ -990,18 +1033,8 @@ def pluginMetadata(plugin):
990
1033
  "Plugin `{}` is not installed or does not have entry points for "
991
1034
  "PsychoPy.".format(plugin))
992
1035
 
993
- pkg = pkg_resources.get_distribution(plugin)
994
- metadata = pkg.get_metadata(pkg.PKG_INFO)
995
-
996
- metadict = {}
997
- for line in metadata.split('\n'):
998
- if not line:
999
- continue
1000
-
1001
- line = line.strip().split(': ')
1002
- if len(line) == 2:
1003
- field, value = line
1004
- metadict[field] = value
1036
+ pkg = importlib.metadata.distribution(plugin)
1037
+ metadict = dict(pkg.metadata)
1005
1038
 
1006
1039
  return metadict
1007
1040
 
@@ -1072,7 +1105,6 @@ def activatePlugins(which='all'):
1072
1105
  # load each plugin and apply any changes to Builder
1073
1106
  for plugin in listPlugins(which):
1074
1107
  loadPlugin(plugin)
1075
- loadPluginBuilderElements(plugin)
1076
1108
 
1077
1109
 
1078
1110
  # Keep track of currently installed window backends. When a window is loaded,
@@ -0,0 +1,39 @@
1
+ import importlib.metadata
2
+
3
+
4
+ def getEntryPoints(module, submodules=True, flatten=True):
5
+ """
6
+ Get entry points which target a particular module.
7
+
8
+ Parameters
9
+ ----------
10
+ module : str
11
+ Import string for the target module (e.g.
12
+ `"psychopy.iohub.devices"`)
13
+ submodules : bool, optional
14
+ If True, will also get entry points which target a
15
+ submodule of the given module. By default True.
16
+ flatten : bool, optional
17
+ If True, will return a flat list of entry points. If
18
+ False, will return a dict arranged by target group. By
19
+ default True.
20
+ """
21
+ # start off with a blank list/dict
22
+ entryPointsList = []
23
+ entryPointsDict = {}
24
+ # iterate through groups
25
+ for group, points in importlib.metadata.entry_points().items():
26
+ # does this group correspond to the requested module?
27
+ if submodules:
28
+ targeted = group.startswith(module)
29
+ else:
30
+ targeted = group == module
31
+ # if group is targeted, add entry points
32
+ if targeted:
33
+ entryPointsList += points
34
+ entryPointsDict[group] = points
35
+ # return list or dict according to flatten arg
36
+ if flatten:
37
+ return entryPointsList
38
+ else:
39
+ return entryPointsDict
@@ -56,7 +56,7 @@
56
56
  # display tips when starting PsychoPy
57
57
  showStartupTips = boolean(default='True')
58
58
  # what windows to display when PsychoPy starts
59
- defaultView = option('builder', 'coder', 'runner', 'all', default='all')
59
+ defaultView = option('last', 'builder', 'coder', 'runner', 'all', default='last')
60
60
  # reset preferences to defaults on next restart of PsychoPy
61
61
  resetPrefs = boolean(default='False') # default must be False!
62
62
  # save any unsaved preferences before closing the window
@@ -149,8 +149,10 @@
149
149
  forceWindowed = boolean(default=True)
150
150
  # What window size to use when forced to windowed mode
151
151
  forcedWindowSize = list(default=list(800, 600))
152
- # How much output to include in the log files when piloting ('error' is fewest messages, 'debug' is most)
152
+ # How much output to include in the log file when piloting ('error' is fewest messages, 'debug' is most)
153
153
  pilotLoggingLevel = option('error', 'warning', 'data', 'exp', 'info', 'debug', default='debug')
154
+ # How much output to display in the console / app when piloting ('error' is fewest messages, 'debug' is most).
155
+ pilotConsoleLoggingLevel = option('error', 'warning', 'data', 'exp', 'info', 'debug', default='warning')
154
156
  # Show an orange border around the window when in piloting mode
155
157
  showPilotingIndicator = boolean(default=True)
156
158
  # Prevent experiment from enabling rush mode when piloting
@@ -56,7 +56,7 @@
56
56
  # display tips when starting PsychoPy
57
57
  showStartupTips = boolean(default='True')
58
58
  # what windows to display when PsychoPy starts
59
- defaultView = option('builder', 'coder', 'runner', 'all', default='all')
59
+ defaultView = option('last', 'builder', 'coder', 'runner', 'all', default='last')
60
60
  # reset preferences to defaults on next restart of PsychoPy
61
61
  resetPrefs = boolean(default='False') # default must be False!
62
62
  # save any unsaved preferences before closing the window
@@ -149,8 +149,10 @@
149
149
  forceWindowed = boolean(default=True)
150
150
  # What window size to use when forced to windowed mode
151
151
  forcedWindowSize = list(default=list(800, 600))
152
- # How much output to include in the log files when piloting ('error' is fewest messages, 'debug' is most)
152
+ # How much output to include in the log file when piloting ('error' is fewest messages, 'debug' is most)
153
153
  pilotLoggingLevel = option('error', 'warning', 'data', 'exp', 'info', 'debug', default='debug')
154
+ # How much output to display in the console / app when piloting ('error' is fewest messages, 'debug' is most).
155
+ pilotConsoleLoggingLevel = option('error', 'warning', 'data', 'exp', 'info', 'debug', default='warning')
154
156
  # Show an orange border around the window when in piloting mode
155
157
  showPilotingIndicator = boolean(default=True)
156
158
  # Prevent experiment from enabling rush mode when piloting
@@ -56,7 +56,7 @@
56
56
  # display tips when starting PsychoPy
57
57
  showStartupTips = boolean(default='True')
58
58
  # what windows to display when PsychoPy starts
59
- defaultView = option('builder', 'coder', 'runner', 'all', default='all')
59
+ defaultView = option('last', 'builder', 'coder', 'runner', 'all', default='last')
60
60
  # reset preferences to defaults on next restart of PsychoPy
61
61
  resetPrefs = boolean(default='False') # default must be False!
62
62
  # save any unsaved preferences before closing the window
@@ -149,8 +149,10 @@
149
149
  forceWindowed = boolean(default=True)
150
150
  # What window size to use when forced to windowed mode
151
151
  forcedWindowSize = list(default=list(800, 600))
152
- # How much output to include in the log files when piloting ('error' is fewest messages, 'debug' is most)
152
+ # How much output to include in the log file when piloting ('error' is fewest messages, 'debug' is most)
153
153
  pilotLoggingLevel = option('error', 'warning', 'data', 'exp', 'info', 'debug', default='debug')
154
+ # How much output to display in the console / app when piloting ('error' is fewest messages, 'debug' is most).
155
+ pilotConsoleLoggingLevel = option('error', 'warning', 'data', 'exp', 'info', 'debug', default='warning')
154
156
  # Show an orange border around the window when in piloting mode
155
157
  showPilotingIndicator = boolean(default=True)
156
158
  # Prevent experiment from enabling rush mode when piloting