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
@@ -898,9 +898,13 @@ class SurveyCtrl(wx.TextCtrl, _ValidatorMixin, _HideMixin):
898
898
 
899
899
 
900
900
  class TableCtrl(wx.TextCtrl, _ValidatorMixin, _HideMixin, _FileMixin):
901
- def __init__(self, parent, valType,
902
- val="", fieldName="",
901
+ def __init__(self, parent, param, fieldName="",
903
902
  size=wx.Size(-1, 24)):
903
+ # get val and val type
904
+ val = param.val
905
+ valType = param.valType
906
+ # store param
907
+ self.param = param
904
908
  # Create self
905
909
  wx.TextCtrl.__init__(self)
906
910
  self.Create(parent, -1, val, name=fieldName, size=size)
@@ -920,19 +924,6 @@ class TableCtrl(wx.TextCtrl, _ValidatorMixin, _HideMixin, _FileMixin):
920
924
  self.xlBtn.SetToolTip(_translate("Open/create in your default table editor"))
921
925
  self.xlBtn.Bind(wx.EVT_BUTTON, self.openExcel)
922
926
  self._szr.Add(self.xlBtn)
923
- # Link to Excel templates for certain contexts
924
- cmpRoot = Path(experiment.components.__file__).parent
925
- expRoot = Path(cmpRoot).parent
926
- self.templates = {
927
- 'Form': Path(cmpRoot) / "form" / "formItems.xltx",
928
- 'CounterBalance': Path(expRoot) / "routines" / "counterbalance" / "counterbalanceItems.xltx",
929
- 'TrialHandler': Path(expRoot) / "loopTemplate.xltx",
930
- 'StairHandler': Path(expRoot) / "loopTemplate.xltx",
931
- 'MultiStairHandler:simple': Path(expRoot) / "staircaseTemplate.xltx",
932
- 'MultiStairHandler:QUEST': Path(expRoot) / "questTemplate.xltx",
933
- 'MultiStairHandler:QUESTPLUS': Path() / "questPlugTemplate.xltx",
934
- 'None': Path(expRoot) / 'blankTemplate.xltx',
935
- }
936
927
  # Specify valid extensions
937
928
  self.validExt = [".csv",".tsv",".txt",
938
929
  ".xl",".xlsx",".xlsm",".xlsb",".xlam",".xltx",".xltm",".xls",".xlt",
@@ -950,32 +941,15 @@ class TableCtrl(wx.TextCtrl, _ValidatorMixin, _HideMixin, _FileMixin):
950
941
  def validate(self, evt=None):
951
942
  """Redirect validate calls to global validate method, assigning appropriate valType"""
952
943
  validate(self, "file")
953
- # Disable Excel button if value is from a variable
954
- if "$" in self.GetValue():
955
- self.xlBtn.Disable()
956
- return
957
- # enable Excel button if valid
958
- self.xlBtn.Enable(self.valid)
959
- # get frame
960
- frame = self.GetParent()
961
- if frame is None:
962
- frame = self.GetTopLevelParent()
963
- while hasattr(frame, "GetParent") and not (
964
- hasattr(frame, "routine") or hasattr(frame, "component") or hasattr(frame, "type")
965
- ):
966
- frame = frame.GetParent()
967
- # get comp type from frame
968
- if hasattr(frame, "component"):
969
- thisType = frame.component.type
970
- elif hasattr(frame, "routine"):
971
- thisType = frame.routine.type
972
- elif hasattr(frame, "type"):
973
- thisType = frame.type
944
+ # if field is blank, enable/diable according to whether there's a template
945
+ if not self.GetValue().strip():
946
+ self.xlBtn.Enable("template" in self.param.ctrlParams)
947
+ # otherwise, enable/disable according to validity
974
948
  else:
975
- thisType = None
976
- # does this component have a default template?
977
- if thisType in self.templates:
978
- self.xlBtn.Enable(True)
949
+ self.xlBtn.Enable(self.valid)
950
+ # if value isn't known until runtime, always disable Excel button
951
+ if "$" in self.GetValue():
952
+ self.xlBtn.Disable()
979
953
 
980
954
  def openExcel(self, event):
981
955
  """Either open the specified excel sheet, or make a new one from a template"""
@@ -986,24 +960,17 @@ class TableCtrl(wx.TextCtrl, _ValidatorMixin, _HideMixin, _FileMixin):
986
960
  "please remember to add it to {name}").format(name=_translate(self.Name)),
987
961
  caption=_translate("Reminder"))
988
962
  dlg.ShowModal()
989
- # get frame
990
- frame = self.GetParent()
991
- while hasattr(frame, "GetParent") and not (hasattr(frame, "routine") or hasattr(frame, "component")):
992
- frame = frame.GetParent()
993
- # get comp type from frame
994
- if hasattr(frame, "component"):
995
- thisType = frame.component.type
996
- elif hasattr(frame, "routine"):
997
- thisType = frame.routine.type
998
- elif hasattr(frame, "type"):
999
- thisType = frame.type
1000
- else:
1001
- thisType = "None"
1002
- # open type specific template, or blank
1003
- if thisType in self.templates:
1004
- file = self.templates[thisType]
963
+ # get template
964
+ if "template" in self.param.ctrlParams:
965
+ file = self.param.ctrlParams['template']
966
+ # if template is specified as a method, call it now to get the value live
967
+ if callable(file):
968
+ file = file()
969
+ # convert to Path
970
+ file = Path(file)
1005
971
  else:
1006
- file = self.templates['None']
972
+ # use blank template if none given
973
+ file = Path(experiment.__file__).parent / 'blankTemplate.xltx',
1007
974
  # Open whatever file is used
1008
975
  try:
1009
976
  os.startfile(file)
@@ -13,12 +13,12 @@ import psychopy.experiment.utils
13
13
  from psychopy.tools import stringtools
14
14
  from psychopy.localization import _translate
15
15
  from . import experiment
16
- from pkg_resources import parse_version
16
+ from packaging.version import Version
17
17
  from psychopy.tools.fontmanager import FontManager
18
18
 
19
19
  fontMGR = FontManager()
20
20
 
21
- if parse_version(wx.__version__) < parse_version('4.0.0a1'):
21
+ if Version(wx.__version__) < Version('4.0.0a1'):
22
22
  _ValidatorBase = wx.PyValidator
23
23
  else:
24
24
  _ValidatorBase = wx.Validator
@@ -106,14 +106,6 @@ class BaseCodeEditor(wx.stc.StyledTextCtrl, handlers.ThemeMixin):
106
106
  deleteItem = wx.MenuItem(menu, self.DeleteID, _translate("Delete"))
107
107
  selectItem = wx.MenuItem(menu, self.SelectAllID, _translate("Select All"))
108
108
 
109
- # Check whether items should be enabled
110
- undoItem.Enable(self.CanUndo())
111
- redoItem.Enable(self.CanRedo())
112
- cutItem.Enable(self.CanCut())
113
- copyItem.Enable(self.CanCopy())
114
- pasteItem.Enable(self.CanPaste())
115
- deleteItem.Enable(self.CanCopy())
116
-
117
109
  # Append items to menu
118
110
  menu.Append(undoItem)
119
111
  menu.Append(redoItem)
@@ -125,6 +117,14 @@ class BaseCodeEditor(wx.stc.StyledTextCtrl, handlers.ThemeMixin):
125
117
  menu.Append(deleteItem)
126
118
  menu.Append(selectItem)
127
119
 
120
+ # Check whether items should be enabled
121
+ undoItem.Enable(self.CanUndo())
122
+ redoItem.Enable(self.CanRedo())
123
+ cutItem.Enable(self.CanCut())
124
+ copyItem.Enable(self.CanCopy())
125
+ pasteItem.Enable(self.CanPaste())
126
+ deleteItem.Enable(self.CanCopy())
127
+
128
128
  self.PopupMenu(menu)
129
129
  menu.Destroy()
130
130
 
@@ -2070,6 +2070,7 @@ class CoderFrame(BaseAuiFrame, handlers.ThemeMixin):
2070
2070
  # self.OnFindClose(None)
2071
2071
 
2072
2072
  def OnFindClose(self, event):
2073
+ self.findDlg.Destroy()
2073
2074
  self.findDlg = None
2074
2075
 
2075
2076
  def OnFileHistory(self, evt=None):
@@ -2873,10 +2874,6 @@ class CoderFrame(BaseAuiFrame, handlers.ThemeMixin):
2873
2874
  # TODO: Allow user to run project from coder
2874
2875
  pass
2875
2876
 
2876
- def setPavloviaUser(self, user):
2877
- # TODO: update user icon on button to user avatar
2878
- pass
2879
-
2880
2877
  def resetPrefs(self, event):
2881
2878
  """Reset preferences to default"""
2882
2879
  # Present "are you sure" dialog
@@ -3056,6 +3053,9 @@ class CoderRibbon(ribbon.FrameRibbon):
3056
3053
 
3057
3054
  self.addSeparator()
3058
3055
 
3056
+ # --- Plugin sections ---
3057
+ self.addPluginSections("psychopy.app.builder")
3058
+
3059
3059
  # --- Views ---
3060
3060
  self.addStretchSpacer()
3061
3061
  self.addSeparator()
@@ -36,10 +36,10 @@ def sendUsageStats(app=None):
36
36
  OSXver, junk, architecture = platform.mac_ver()
37
37
  systemInfo = "OSX_%s" % (OSXver)
38
38
  elif sys.platform.startswith('linux'):
39
- from distro import linux_distribution
39
+ import distro
40
40
  systemInfo = '%s_%s_%s' % (
41
41
  'Linux',
42
- ':'.join([x for x in linux_distribution() if x != '']),
42
+ ':'.join([x for x in [distro.name(), distro.version(), distro.codename()] if x != '']),
43
43
  platform.release())
44
44
  if len(systemInfo) > 30: # if it's too long PHP/SQL fails to store!?
45
45
  systemInfo = systemInfo[0:30]
@@ -12,7 +12,7 @@ import time
12
12
  import zipfile
13
13
  import platform
14
14
  import os
15
- from pkg_resources import parse_version
15
+ from packaging.version import Version
16
16
  import wx
17
17
  import wx.lib.filebrowsebutton
18
18
  try:
@@ -116,8 +116,8 @@ class Updater():
116
116
  raise(err)
117
117
  skip = self.app.prefs.appData['skipVersion'] == self.latest['version']
118
118
  if newer and not skip:
119
- if (parse_version(self.latest['lastUpdatable'])
120
- <= parse_version(self.runningVersion)):
119
+ if (Version(self.latest['lastUpdatable'])
120
+ <= Version(self.runningVersion)):
121
121
  # go to the updating window
122
122
  confirmDlg = SuggestUpdateDialog(
123
123
  self.latest, self.runningVersion)
@@ -338,8 +338,8 @@ class InstallUpdateDialog(wx.Dialog):
338
338
  msg += _translate("Check proxy settings in preferences.")
339
339
  self.statusMessage.SetLabel(msg)
340
340
  return
341
- elif (parse_version(self.latest['version'])
342
- < parse_version(self.runningVersion)):
341
+ elif (Version(self.latest['version'])
342
+ < Version(self.runningVersion)):
343
343
  msg = _translate(
344
344
  "You are running PsychoPy (%(running)s), which is ahead of "
345
345
  "the latest official version (%(latest)s)") % {
@@ -354,8 +354,8 @@ class InstallUpdateDialog(wx.Dialog):
354
354
  "PsychoPy v%(latest)s is available\nYou are running v%(running)s")
355
355
  msg = txt % {'latest': self.latest['version'],
356
356
  'running': self.runningVersion}
357
- if (parse_version(self.latest['lastUpdatable'])
358
- <= parse_version(self.runningVersion)):
357
+ if (Version(self.latest['lastUpdatable'])
358
+ <= Version(self.runningVersion)):
359
359
  msg += _translate("\nYou can update to the latest version automatically")
360
360
  else:
361
361
  msg += _translate("\nYou cannot update to the latest version "
@@ -620,10 +620,10 @@ def sendUsageStats():
620
620
  OSXver, junk, architecture = platform.mac_ver()
621
621
  systemInfo = "OSX_%s_%s" % (OSXver, architecture)
622
622
  elif sys.platform.startswith('linux'):
623
- from distro import linux_distribution
623
+ import distro
624
624
  systemInfo = '%s_%s_%s' % (
625
625
  'Linux',
626
- ':'.join([x for x in linux_distribution() if x != '']),
626
+ ':'.join([x for x in [distro.name(), distro.version(), distro.codename()] if x != '']),
627
627
  platform.release())
628
628
  if len(systemInfo) > 30: # if it's too long PHP/SQL fails to store!?
629
629
  systemInfo = systemInfo[0:30]
psychopy/app/dialogs.py CHANGED
@@ -18,7 +18,7 @@ from wx.lib.newevent import NewEvent
18
18
 
19
19
  from psychopy import logging
20
20
  from psychopy.localization import _translate
21
- from pkg_resources import parse_version
21
+ from packaging.version import Version
22
22
 
23
23
 
24
24
  class MessageDialog(wx.Dialog):
@@ -79,6 +79,38 @@ class MessageDialog(wx.Dialog):
79
79
  (GBSizerExLayoutEvent, EVT_GBSIZEREX_LAYOUT) = NewEvent()
80
80
 
81
81
 
82
+ class RichMessageDialog(wx.Dialog):
83
+ def __init__(
84
+ self,
85
+ parent=None,
86
+ message="",
87
+ title="",
88
+ size=(600, 500),
89
+ style=wx.RESIZE_BORDER
90
+ ):
91
+ from psychopy.app.utils import MarkdownCtrl
92
+ # initialise dialog
93
+ wx.Dialog.__init__(
94
+ self, parent,
95
+ title=title,
96
+ size=size,
97
+ style=style
98
+ )
99
+ # setup sizer
100
+ self.border = wx.BoxSizer(wx.VERTICAL)
101
+ self.SetSizer(self.border)
102
+ self.sizer = wx.BoxSizer(wx.VERTICAL)
103
+ self.border.Add(self.sizer, proportion=1, border=6, flag=wx.EXPAND | wx.ALL)
104
+ # add markdown ctrl
105
+ self.ctrl = MarkdownCtrl(
106
+ self, value=message, style=wx.TE_READONLY
107
+ )
108
+ self.sizer.Add(self.ctrl, border=6, proportion=1, flag=wx.EXPAND | wx.ALL)
109
+ # add OK button
110
+ self.btns = self.CreateStdDialogButtonSizer(flags=wx.OK)
111
+ self.border.Add(self.btns, border=12, flag=wx.EXPAND | wx.ALL)
112
+
113
+
82
114
  class GlobSizer(wx.GridBagSizer):
83
115
  """This is a GridBagSizer that supports adding/removing/inserting rows and
84
116
  columns. It was found online, with not clear use license (public domain?).
@@ -620,7 +652,7 @@ class ListWidget(GlobSizer):
620
652
 
621
653
 
622
654
  if __name__ == '__main__':
623
- if parse_version(wx.__version__) < parse_version('2.9'):
655
+ if Version(wx.__version__) < Version('2.9'):
624
656
  app = wx.PySimpleApp()
625
657
  else:
626
658
  app = wx.App(False)
psychopy/app/idle.py CHANGED
@@ -82,6 +82,37 @@ tasks['getPavloviaUser'] = {
82
82
  currentTask = None
83
83
 
84
84
 
85
+ def addTask(taskName, func, tstart=None, tend=None, thread=True):
86
+ """Add an idle task.
87
+
88
+ Parameters
89
+ ----------
90
+ taskName : str
91
+ Name of the task.
92
+ func : function
93
+ Function to be executed.
94
+ tstart : float, optional
95
+ Start time of the task.
96
+ tend : float, optional
97
+ End time of the task.
98
+ thread : bool, optional
99
+ Whether to run the task in a separate thread.
100
+
101
+ """
102
+ global tasks
103
+ if taskName in tasks:
104
+ logging.warning('Task {} already exists'.format(taskName))
105
+ return
106
+
107
+ tasks[taskName] = {
108
+ 'status': NOT_STARTED,
109
+ 'func': func,
110
+ 'tstart': tstart,
111
+ 'tEnd': tend,
112
+ 'thread': thread,
113
+ }
114
+
115
+
85
116
  def doIdleTasks(app=None):
86
117
  global currentTask
87
118
 
psychopy/app/jobs.py CHANGED
@@ -37,6 +37,7 @@ import os.path
37
37
 
38
38
  import wx
39
39
  import os
40
+ import sys
40
41
  from subprocess import Popen, PIPE
41
42
  from threading import Thread, Event
42
43
  from queue import Queue, Empty
@@ -246,6 +247,22 @@ class Job:
246
247
  # start the sub-process
247
248
  command = self._command
248
249
 
250
+ # # subprocess inherits the environment of the parent process
251
+ if env is None:
252
+ scriptEnv = os.environ.copy()
253
+ else:
254
+ scriptEnv = env
255
+
256
+ # remove some environment variables that can cause issues
257
+ if 'PYTHONSTARTUP' in scriptEnv:
258
+ del scriptEnv['PYTHONSTARTUP']
259
+
260
+ # Set encoding for text mode pipes, needs to be explicitly set or we
261
+ # crash on windows
262
+ scriptEnv['PYTHONIOENCODING'] = 'utf-8'
263
+ if sys.platform == 'win32':
264
+ scriptEnv['PYTHONLEGACYWINDOWSSTDIO'] = 'utf-8'
265
+
249
266
  try:
250
267
  self._process = Popen(
251
268
  args=command,
@@ -257,10 +274,11 @@ class Job:
257
274
  preexec_fn=None,
258
275
  shell=False,
259
276
  cwd=cwd,
260
- env=env,
261
- universal_newlines=True, # gives us back a string instead of bytes
277
+ env=scriptEnv,
278
+ # universal_newlines=True, # gives us back a string instead of bytes
262
279
  creationflags=0,
263
- text=True
280
+ text=False,
281
+ encoding='utf-8'
264
282
  )
265
283
  except FileNotFoundError:
266
284
  return -1 # negative PID means failure
@@ -19,6 +19,7 @@ import sys
19
19
 
20
20
  import wx
21
21
  from .ui import BaseLinuxConfigDialog
22
+ from ...core import rush
22
23
 
23
24
  # Text that appears at the top of the dialog with provides instructions to the
24
25
  # user.
@@ -142,3 +143,11 @@ def linuxConfigFileExists():
142
143
  return True
143
144
 
144
145
  return os.path.isfile(_confPath)
146
+
147
+ def linuxRushAllowed():
148
+ if sys.platform != 'linux':
149
+ return True
150
+
151
+ success = rush(1)
152
+ rush(0)
153
+ return success