psychopy 2024.1.3__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.
- psychopy/.DS_Store +0 -0
- psychopy/CHANGELOG.txt +206 -0
- psychopy/GIT_SHA +1 -0
- psychopy/VERSION +1 -0
- psychopy/__init__.py +77 -15
- psychopy/app/Resources/classic/plugin16.png +0 -0
- psychopy/app/Resources/classic/plugin16@2x.png +0 -0
- psychopy/app/Resources/dark/plugin16.png +0 -0
- psychopy/app/Resources/dark/plugin16@2x.png +0 -0
- psychopy/app/Resources/light/plugin16.png +0 -0
- psychopy/app/Resources/light/plugin16@2x.png +0 -0
- psychopy/app/__init__.py +76 -2
- psychopy/app/_psychopyApp.py +126 -101
- psychopy/app/builder/builder.py +14 -10
- psychopy/app/builder/dialogs/__init__.py +8 -8
- psychopy/app/builder/dialogs/dlgsConditions.py +12 -13
- psychopy/app/builder/dialogs/paramCtrls.py +24 -57
- psychopy/app/builder/localizedStrings.py +11 -9
- psychopy/app/builder/validators.py +2 -2
- psychopy/app/coder/codeEditorBase.py +8 -8
- psychopy/app/coder/coder.py +4 -4
- psychopy/app/connections/sendusage.py +2 -2
- psychopy/app/connections/updates.py +9 -9
- psychopy/app/dialogs.py +34 -2
- psychopy/app/idle.py +31 -0
- psychopy/app/jobs.py +21 -3
- psychopy/app/linuxconfig/__init__.py +9 -0
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +4602 -2540
- psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_CO/LC_MESSAGE/messages.po +56 -54
- psychopy/app/locale/es_ES/LC_MESSAGE/messages.po +53 -43
- psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_US/LC_MESSAGE/messages.po +56 -54
- psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ja_JP/LC_MESSAGE/messages.po +1258 -1176
- psychopy/app/locale/pt_PT/LC_MESSAGE/messages.po +9415 -5
- psychopy/app/pavlovia_ui/_base.py +33 -3
- psychopy/app/pavlovia_ui/search.py +0 -1
- psychopy/app/plugin_manager/dialog.py +104 -51
- psychopy/app/plugin_manager/packages.py +5 -0
- psychopy/app/plugin_manager/plugins.py +152 -67
- psychopy/app/preferencesDlg.py +8 -8
- psychopy/app/psychopyApp.py +11 -5
- psychopy/app/ribbon.py +124 -14
- psychopy/app/runner/runner.py +6 -1
- psychopy/app/stdout/stdOutRich.py +27 -11
- psychopy/app/themes/icons.py +52 -2
- psychopy/assets/__init__.py +0 -0
- psychopy/assets/click.png +0 -0
- psychopy/assets/clicknext.png +0 -0
- psychopy/assets/next.png +0 -0
- psychopy/assets/psychopy.ico +0 -0
- psychopy/assets/psychopy.png +0 -0
- psychopy/assets/templates/__init__.py +0 -0
- psychopy/assets/touch.png +0 -0
- psychopy/assets/touchnext.png +0 -0
- psychopy/assets/window.ico +0 -0
- psychopy/changes/2023.1.0.md +9 -0
- psychopy/changes/2024.1.0.md +16 -0
- psychopy/changes/__init__.py +0 -0
- psychopy/clock.py +2 -2
- psychopy/colors.py +2 -1
- psychopy/compatibility.py +53 -1
- psychopy/contrib/.DS_Store +0 -0
- psychopy/contrib/configobj/__init__.py +10 -8
- psychopy/data/__init__.py +3 -2
- psychopy/data/base.py +5 -5
- psychopy/data/experiment.py +130 -4
- psychopy/data/routine.py +56 -0
- psychopy/data/staircase.py +2 -2
- psychopy/data/trial.py +559 -97
- psychopy/data/utils.py +56 -21
- psychopy/demos/.DS_Store +0 -0
- psychopy/demos/builder/.DS_Store +0 -0
- psychopy/demos/builder/Design Templates/.DS_Store +0 -0
- psychopy/demos/builder/Experiments/.DS_Store +0 -0
- psychopy/demos/builder/Feature Demos/.DS_Store +0 -0
- psychopy/demos/builder/Feature Demos/buttonBox/buttonBoxDemo.psyexp +375 -0
- psychopy/demos/builder/Feature Demos/buttonBox/readme.md +5 -0
- psychopy/demos/builder/Feature Demos/pilotMode/pilotMode.psyexp +433 -0
- psychopy/demos/builder/Feature Demos/pilotMode/readme.md +7 -0
- psychopy/demos/builder/Feature Demos/progress/progressBar.psyexp +4 -4
- psychopy/demos/builder/Hardware/.DS_Store +0 -0
- psychopy/demos/builder/Helper Tools/.DS_Store +0 -0
- psychopy/demos/coder/.DS_Store +0 -0
- psychopy/demos/coder/hardware/testSoundLatency.py +2 -2
- psychopy/demos/coder/iohub/.DS_Store +0 -0
- psychopy/demos/coder/misc/hdf5_2_csv +33 -0
- psychopy/event.py +30 -29
- psychopy/experiment/.DS_Store +0 -0
- psychopy/experiment/_experiment.py +6 -6
- psychopy/experiment/components/.DS_Store +0 -0
- psychopy/experiment/components/__init__.py +6 -3
- psychopy/experiment/components/_base.py +286 -131
- psychopy/experiment/components/aperture/.DS_Store +0 -0
- psychopy/experiment/components/brush/.DS_Store +0 -0
- psychopy/experiment/components/button/.DS_Store +0 -0
- psychopy/experiment/components/button/__init__.py +5 -1
- psychopy/experiment/components/buttonBox/.DS_Store +0 -0
- psychopy/experiment/components/buttonBox/__init__.py +21 -12
- psychopy/experiment/components/camera/.DS_Store +0 -0
- psychopy/experiment/components/code/.DS_Store +0 -0
- psychopy/experiment/components/dots/.DS_Store +0 -0
- psychopy/experiment/components/eyetracker_record/.DS_Store +0 -0
- psychopy/experiment/components/eyetracker_record/__init__.py +92 -30
- psychopy/experiment/components/form/.DS_Store +0 -0
- psychopy/experiment/components/form/__init__.py +6 -2
- psychopy/experiment/components/grating/.DS_Store +0 -0
- psychopy/experiment/components/grating/__init__.py +14 -3
- psychopy/experiment/components/image/.DS_Store +0 -0
- psychopy/experiment/components/image/__init__.py +14 -3
- psychopy/experiment/components/joyButtons/.DS_Store +0 -0
- psychopy/experiment/components/joystick/.DS_Store +0 -0
- psychopy/experiment/components/keyboard/.DS_Store +0 -0
- psychopy/experiment/components/keyboard/__init__.py +22 -10
- psychopy/experiment/components/microphone/.DS_Store +0 -0
- psychopy/experiment/components/microphone/__init__.py +59 -39
- psychopy/experiment/components/mouse/.DS_Store +0 -0
- psychopy/experiment/components/mouse/__init__.py +44 -29
- psychopy/experiment/components/movie/.DS_Store +0 -0
- psychopy/experiment/components/movie/__init__.py +1 -1
- psychopy/experiment/components/panorama/.DS_Store +0 -0
- psychopy/experiment/components/parallelOut/.DS_Store +0 -0
- psychopy/experiment/components/patch/.DS_Store +0 -0
- psychopy/experiment/components/polygon/.DS_Store +0 -0
- psychopy/experiment/components/polygon/__init__.py +26 -6
- psychopy/experiment/components/progress/.DS_Store +0 -0
- psychopy/experiment/components/progress/__init__.py +1 -1
- psychopy/experiment/components/ratingScale/.DS_Store +0 -0
- psychopy/experiment/components/resourceManager/.DS_Store +0 -0
- psychopy/experiment/components/roi/.DS_Store +0 -0
- psychopy/experiment/components/roi/__init__.py +5 -0
- psychopy/experiment/components/routineSettings/.DS_Store +0 -0
- psychopy/experiment/components/routineSettings/__init__.py +57 -10
- psychopy/experiment/components/serialOut/.DS_Store +0 -0
- psychopy/experiment/components/settings/.DS_Store +0 -0
- psychopy/experiment/components/settings/__init__.py +117 -42
- psychopy/experiment/components/slider/.DS_Store +0 -0
- psychopy/experiment/components/sound/.DS_Store +0 -0
- psychopy/experiment/components/sound/__init__.py +54 -19
- psychopy/experiment/components/static/.DS_Store +0 -0
- psychopy/experiment/components/static/__init__.py +1 -1
- psychopy/experiment/components/text/.DS_Store +0 -0
- psychopy/experiment/components/text/__init__.py +28 -3
- psychopy/experiment/components/textbox/.DS_Store +0 -0
- psychopy/experiment/components/textbox/__init__.py +12 -2
- psychopy/experiment/components/unknown/.DS_Store +0 -0
- psychopy/experiment/components/unknown/__init__.py +1 -2
- psychopy/experiment/components/unknownPlugin/.DS_Store +0 -0
- psychopy/experiment/components/unknownPlugin/__init__.py +2 -2
- psychopy/experiment/components/variable/.DS_Store +0 -0
- psychopy/experiment/flow.py +11 -4
- psychopy/experiment/loops.py +85 -37
- psychopy/experiment/params.py +74 -32
- psychopy/experiment/py2js_transpiler.py +8 -1
- psychopy/experiment/routines/.DS_Store +0 -0
- psychopy/experiment/routines/_base.py +102 -22
- psychopy/experiment/routines/counterbalance/.DS_Store +0 -0
- psychopy/experiment/routines/counterbalance/__init__.py +5 -1
- psychopy/experiment/routines/eyetracker_calibrate/.DS_Store +0 -0
- psychopy/experiment/routines/eyetracker_validate/.DS_Store +0 -0
- psychopy/experiment/routines/pavlovia_survey/.DS_Store +0 -0
- psychopy/experiment/routines/photodiodeValidator/.DS_Store +0 -0
- psychopy/experiment/routines/photodiodeValidator/__init__.py +7 -6
- psychopy/experiment/routines/unknown/.DS_Store +0 -0
- psychopy/gui/wxgui.py +4 -4
- psychopy/hardware/.DS_Store +0 -0
- psychopy/hardware/__init__.py +1 -1
- psychopy/hardware/base.py +12 -0
- psychopy/hardware/camera/__init__.py +1 -15
- psychopy/hardware/cedrus.py +10 -11
- psychopy/hardware/crs/colorcal.py +13 -22
- psychopy/hardware/crs/optical.py +10 -20
- psychopy/hardware/emulator.py +17 -14
- psychopy/hardware/eyetracker.py +42 -118
- psychopy/hardware/gammasci.py +4 -15
- psychopy/hardware/keyboard.py +102 -11
- psychopy/hardware/listener.py +3 -0
- psychopy/hardware/microphone.py +148 -18
- psychopy/hardware/minolta.py +8 -15
- psychopy/hardware/photodiode.py +191 -16
- psychopy/hardware/photometer/__init__.py +11 -19
- psychopy/hardware/pr.py +8 -15
- psychopy/hardware/speaker.py +39 -4
- psychopy/info.py +0 -71
- psychopy/iohub/.DS_Store +0 -0
- psychopy/iohub/__init__.py +1 -1
- psychopy/iohub/client/__init__.py +30 -20
- psychopy/iohub/client/keyboard.py +24 -24
- psychopy/iohub/datastore/__init__.py +2 -2
- psychopy/iohub/datastore/util.py +2 -2
- psychopy/iohub/default_config.yaml +1 -1
- psychopy/iohub/devices/.DS_Store +0 -0
- psychopy/iohub/devices/__init__.py +112 -25
- psychopy/iohub/devices/deviceConfigValidation.py +2 -1
- psychopy/iohub/devices/experiment/default_experiment.yaml +12 -1
- psychopy/iohub/devices/experiment/supported_config_settings.yaml +5 -1
- psychopy/iohub/devices/eyetracker/.DS_Store +0 -0
- psychopy/iohub/devices/eyetracker/__init__.py +46 -0
- psychopy/iohub/devices/eyetracker/calibration/procedure.py +2 -2
- psychopy/iohub/devices/eyetracker/hw/gazepoint/__init__.py +14 -2
- psychopy/iohub/devices/eyetracker/hw/mouse/eyetracker.py +3 -4
- psychopy/iohub/server.py +2 -2
- psychopy/iohub/start_iohub_process.py +3 -0
- psychopy/iohub/util/__init__.py +62 -70
- psychopy/layout.py +5 -5
- psychopy/logging.py +8 -1
- psychopy/microphone.py +10 -37
- psychopy/platform_specific/__init__.py +0 -2
- psychopy/platform_specific/darwin.py +1 -3
- psychopy/platform_specific/linux.py +31 -33
- psychopy/platform_specific/win32.py +38 -13
- psychopy/plugins/__init__.py +148 -116
- psychopy/plugins/util.py +39 -0
- psychopy/preferences/Darwin.spec +4 -2
- psychopy/preferences/FreeBSD.spec +4 -2
- psychopy/preferences/Linux.spec +4 -2
- psychopy/preferences/Windows.spec +4 -2
- psychopy/preferences/baseNoArch.spec +4 -2
- psychopy/preferences/preferences.py +47 -24
- psychopy/projects/pavlovia.py +47 -4
- psychopy/scripts/psyexpCompile.py +0 -4
- psychopy/session.py +153 -21
- psychopy/sound/__init__.py +31 -21
- psychopy/sound/_base.py +20 -3
- psychopy/sound/audioclip.py +320 -33
- psychopy/sound/backend_ptb.py +47 -58
- psychopy/sound/backend_pygame.py +1 -1
- psychopy/sound/backend_pysound.py +6 -15
- psychopy/sound/transcribe.py +53 -0
- psychopy/tests/.DS_Store +0 -0
- psychopy/tests/data/.DS_Store +0 -0
- psychopy/tests/data/TestUnknownPluginComponent_load_resave.psyexp +135 -0
- psychopy/tests/data/Test_textbox/test_ori_0_bottom right.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_0_center.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_0_top left.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_120_bottom right.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_120_center.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_120_top left.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_180_bottom right.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_180_center.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_180_top left.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_240_bottom right.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_240_center.png +0 -0
- psychopy/tests/data/Test_textbox/test_ori_240_top left.png +0 -0
- psychopy/tests/data/correctScript/.DS_Store +0 -0
- psychopy/tests/data/test_components/testClearKeyboard/testClearKeyboard.psyexp +200 -0
- psychopy/tests/data/test_session/.DS_Store +0 -0
- psychopy/tests/data/test_session/root/testFutureTrials/testFutureTrials.psyexp +155 -0
- psychopy/tests/data/test_session/root/testTrialNav/trialNav.psyexp +158 -0
- psychopy/tests/test_app/.DS_Store +0 -0
- psychopy/tests/test_app/conftest.py +2 -2
- psychopy/tests/test_app/test_speed.py +4 -1
- psychopy/tests/test_data/test_TrialHandler2.py +146 -1
- psychopy/tests/test_experiment/.DS_Store +0 -0
- psychopy/tests/test_experiment/needs_wx/genComponsTemplate.py +3 -3
- psychopy/tests/test_experiment/needs_wx/test_components.py +2 -2
- psychopy/tests/test_experiment/test_components/test_KeyboardComponent.py +28 -0
- psychopy/tests/test_experiment/test_components/test_UnknownPluginComponent.py +27 -0
- psychopy/tests/test_experiment/test_components/test_base_components.py +58 -0
- psychopy/tests/test_experiment/test_py2js.py +1 -1
- psychopy/tests/test_hardware/test_keyboard.py +184 -16
- psychopy/tests/test_hardware/test_ports.py +1 -11
- psychopy/tests/test_liaison/test_Liaison.py +47 -0
- psychopy/tests/test_misc/test_core.py +5 -0
- psychopy/tests/test_session/test_Session.py +5 -1
- psychopy/tests/test_tools/test_versionchooser.py +39 -8
- psychopy/tests/test_visual/test_all_stimuli.py +0 -97
- psychopy/tests/test_visual/test_image.py +6 -5
- psychopy/tests/test_visual/test_textbox.py +36 -0
- psychopy/tests/utils.py +4 -0
- psychopy/tools/filetools.py +1 -1
- psychopy/tools/pkgtools.py +160 -137
- psychopy/tools/versionchooser.py +10 -10
- psychopy/tools/wizard.py +3 -3
- psychopy/visual/.DS_Store +0 -0
- psychopy/visual/backends/pygletbackend.py +24 -13
- psychopy/visual/basevisual.py +5 -11
- psychopy/visual/button.py +2 -14
- psychopy/visual/helpers.py +5 -5
- psychopy/visual/line.py +1 -2
- psychopy/visual/movie2.py +7 -816
- psychopy/visual/movie3.py +7 -589
- psychopy/visual/movies/__init__.py +8 -11
- psychopy/visual/movies/frame.py +5 -2
- psychopy/visual/movies/players/ffpyplayer_player.py +5 -2
- psychopy/visual/noise.py +8 -7
- psychopy/visual/patch.py +7 -16
- psychopy/visual/progress.py +1 -1
- psychopy/visual/radial.py +9 -7
- psychopy/visual/ratingscale.py +8 -1415
- psychopy/visual/secondorder.py +10 -9
- psychopy/visual/shape.py +7 -2
- psychopy/visual/text.py +1 -1
- psychopy/visual/textbox2/textbox2.py +28 -5
- psychopy/web.py +5 -2
- {psychopy-2024.1.3.dist-info → psychopy-2024.2.0.dist-info}/METADATA +8 -13
- {psychopy-2024.1.3.dist-info → psychopy-2024.2.0.dist-info}/RECORD +313 -219
- {psychopy-2024.1.3.dist-info → psychopy-2024.2.0.dist-info}/WHEEL +1 -1
- psychopy/app/Resources/click.png +0 -0
- psychopy/app/Resources/next.png +0 -0
- psychopy/experiment/components/patch/__init__.py +0 -121
- psychopy/experiment/components/patch/classic/patch.png +0 -0
- psychopy/experiment/components/patch/dark/patch.png +0 -0
- psychopy/experiment/components/patch/dark/patch@2x.png +0 -0
- psychopy/experiment/components/patch/light/patch.png +0 -0
- psychopy/experiment/components/patch/light/patch@2x.png +0 -0
- psychopy/experiment/components/ratingScale/__init__.py +0 -337
- psychopy/experiment/components/ratingScale/classic/ratingscale.png +0 -0
- psychopy/experiment/components/ratingScale/classic/ratingscale@2x.png +0 -0
- psychopy/experiment/components/ratingScale/dark/ratingScale@2x.png +0 -0
- psychopy/experiment/components/ratingScale/dark/ratingscale.png +0 -0
- psychopy/experiment/components/ratingScale/light/ratingScale@2x.png +0 -0
- psychopy/experiment/components/ratingScale/light/ratingscale.png +0 -0
- psychopy/platform_specific/posix.py +0 -16
- psychopy/tests/test_sound/test_microphone.py +0 -217
- psychopy/tests/test_visual/test_ratingScale.py +0 -299
- /psychopy/{app/Resources → assets}/Psychopy Window Favicon@16w.png +0 -0
- /psychopy/{app/Resources → assets}/Psychopy Window Favicon@32w.png +0 -0
- /psychopy/{app/Resources → assets}/USB-C.png +0 -0
- /psychopy/{app/Resources → assets}/USB.png +0 -0
- /psychopy/{app/Resources → assets}/creditCard.png +0 -0
- /psychopy/{app/Resources → assets}/default.mp3 +0 -0
- /psychopy/{app/Resources → assets}/default.mp4 +0 -0
- /psychopy/{app/Resources → assets}/default.png +0 -0
- /psychopy/{app/Resources → assets/templates}/instruct1.png +0 -0
- /psychopy/{app/Resources → assets/templates}/instruct2.png +0 -0
- {psychopy-2024.1.3.dist-info → psychopy-2024.2.0.dist-info}/entry_points.txt +0 -0
- {psychopy-2024.1.3.dist-info → psychopy-2024.2.0.dist-info}/licenses/AUTHORS.md +0 -0
- {psychopy-2024.1.3.dist-info → psychopy-2024.2.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -8,6 +8,7 @@ import sys
|
|
|
8
8
|
|
|
9
9
|
import wx
|
|
10
10
|
import wx.html2
|
|
11
|
+
import requests
|
|
11
12
|
|
|
12
13
|
from psychopy.localization import _translate
|
|
13
14
|
from psychopy.projects import pavlovia
|
|
@@ -90,8 +91,9 @@ class PavloviaMiniBrowser(wx.Dialog):
|
|
|
90
91
|
self._loggingIn = True
|
|
91
92
|
authURL, state = pavlovia.getAuthURL()
|
|
92
93
|
self.browser.Bind(wx.html2.EVT_WEBVIEW_ERROR, self.onConnectionErr)
|
|
93
|
-
self.browser.Bind(wx.html2.EVT_WEBVIEW_LOADED, self.
|
|
94
|
+
self.browser.Bind(wx.html2.EVT_WEBVIEW_LOADED, self.getAccessTokenFromURL)
|
|
94
95
|
self.browser.LoadURL(authURL)
|
|
96
|
+
self.Close()
|
|
95
97
|
|
|
96
98
|
def setURL(self, url):
|
|
97
99
|
self.browser.LoadURL(url)
|
|
@@ -113,10 +115,38 @@ class PavloviaMiniBrowser(wx.Dialog):
|
|
|
113
115
|
if 'INET_E_DOWNLOAD_FAILURE' in event.GetString():
|
|
114
116
|
self.EndModal(wx.ID_EXIT)
|
|
115
117
|
raise Exception("{}: No internet connection available.".format(event.GetString()))
|
|
118
|
+
|
|
119
|
+
def getAccessTokenFromURL(self, event):
|
|
120
|
+
"""
|
|
121
|
+
Parse the redirect url from a login request for the parameter `code`, this is
|
|
122
|
+
the "Auth code" which is used later to get an access token.
|
|
116
123
|
|
|
117
|
-
|
|
124
|
+
Parameters
|
|
125
|
+
----------
|
|
126
|
+
event : wx.html2.EVT_WEBVIEW_LOADED
|
|
127
|
+
Load event from the browser window.
|
|
128
|
+
"""
|
|
129
|
+
# get URL
|
|
118
130
|
url = event.GetURL()
|
|
119
|
-
|
|
131
|
+
# get auth code from URL
|
|
132
|
+
if "code=" in url:
|
|
133
|
+
# get state from redirect url
|
|
134
|
+
self.tokenInfo['state'] = self.getParamFromURL('state', url)
|
|
135
|
+
# if returned an auth code, use it to get a token
|
|
136
|
+
resp = requests.post(
|
|
137
|
+
"https://gitlab.pavlovia.org/oauth/token",
|
|
138
|
+
params={
|
|
139
|
+
'client_id': pavlovia.client_id,
|
|
140
|
+
'code': self.getParamFromURL("code", url),
|
|
141
|
+
'grant_type': "authorization_code",
|
|
142
|
+
'redirect_uri': pavlovia.redirect_url,
|
|
143
|
+
'code_verifier': pavlovia.code_verifier
|
|
144
|
+
}
|
|
145
|
+
).json()
|
|
146
|
+
# use the json response from that http request to get access remaining token info
|
|
147
|
+
self.tokenInfo['token'] = resp['access_token']
|
|
148
|
+
self.tokenInfo['tokenType'] = resp['token_type']
|
|
149
|
+
elif "access_token=" in url:
|
|
120
150
|
self.tokenInfo['token'] = self.getParamFromURL(
|
|
121
151
|
'access_token', url)
|
|
122
152
|
self.tokenInfo['tokenType'] = self.getParamFromURL(
|
|
@@ -8,6 +8,7 @@ from psychopy.app import getAppInstance
|
|
|
8
8
|
from psychopy.app.plugin_manager import PluginManagerPanel, PackageManagerPanel, InstallStdoutPanel
|
|
9
9
|
from psychopy.experiment import getAllElements
|
|
10
10
|
from psychopy.localization import _translate
|
|
11
|
+
import psychopy.logging as logging
|
|
11
12
|
import psychopy.tools.pkgtools as pkgtools
|
|
12
13
|
import psychopy.app.jobs as jobs
|
|
13
14
|
import sys
|
|
@@ -18,6 +19,10 @@ import psychopy.plugins as plugins
|
|
|
18
19
|
pkgtools.refreshPackages() # build initial package cache
|
|
19
20
|
|
|
20
21
|
|
|
22
|
+
# flag to indicate if PsychoPy needs to be restarted after installing a package
|
|
23
|
+
NEEDS_RESTART = False
|
|
24
|
+
|
|
25
|
+
|
|
21
26
|
class EnvironmentManagerDlg(wx.Dialog):
|
|
22
27
|
def __init__(self, parent):
|
|
23
28
|
wx.Dialog.__init__(
|
|
@@ -47,7 +52,17 @@ class EnvironmentManagerDlg(wx.Dialog):
|
|
|
47
52
|
self.notebook.InsertPage(1, self.packageMgr, text=_translate("Packages"))
|
|
48
53
|
# Buttons
|
|
49
54
|
self.btns = self.CreateStdDialogButtonSizer(flags=wx.HELP | wx.CLOSE)
|
|
55
|
+
self.Bind(wx.EVT_CLOSE, self.onClose)
|
|
50
56
|
self.border.Add(self.btns, border=12, flag=wx.EXPAND | wx.ALL)
|
|
57
|
+
# store button handles
|
|
58
|
+
self.closeBtn = self.helpBtn = None
|
|
59
|
+
for btn in self.btns.Children:
|
|
60
|
+
if not btn.Window:
|
|
61
|
+
continue
|
|
62
|
+
if btn.Window.GetId() == wx.ID_CLOSE:
|
|
63
|
+
self.closeBtn = btn.Window
|
|
64
|
+
if btn.Window.GetId() == wx.ID_HELP:
|
|
65
|
+
self.helpBtn = btn.Window
|
|
51
66
|
|
|
52
67
|
self.pipProcess = None # handle to the current Job
|
|
53
68
|
|
|
@@ -75,12 +90,14 @@ class EnvironmentManagerDlg(wx.Dialog):
|
|
|
75
90
|
"""
|
|
76
91
|
cmd = [sys.executable, "-m", "pip", "index", "versions", packageName,
|
|
77
92
|
'--no-input', '--no-color']
|
|
93
|
+
env = os.environ.copy()
|
|
78
94
|
# run command in subprocess
|
|
79
95
|
output = sp.Popen(
|
|
80
96
|
cmd,
|
|
81
97
|
stdout=sp.PIPE,
|
|
82
98
|
stderr=sp.PIPE,
|
|
83
99
|
shell=False,
|
|
100
|
+
env=env,
|
|
84
101
|
universal_newlines=True)
|
|
85
102
|
stdout, stderr = output.communicate() # blocks until process exits
|
|
86
103
|
nullVersion = {'All': [], 'Installed': '', 'Latest': ''}
|
|
@@ -166,6 +183,7 @@ class EnvironmentManagerDlg(wx.Dialog):
|
|
|
166
183
|
|
|
167
184
|
# interpreter path
|
|
168
185
|
pyExec = sys.executable
|
|
186
|
+
env = os.environ.copy()
|
|
169
187
|
|
|
170
188
|
# build the shell command to run the script
|
|
171
189
|
command = [pyExec, '-m', 'pip', 'uninstall', packageName, '--yes']
|
|
@@ -179,9 +197,12 @@ class EnvironmentManagerDlg(wx.Dialog):
|
|
|
179
197
|
# flags=execFlags,
|
|
180
198
|
inputCallback=self.output.writeStdOut, # both treated the same
|
|
181
199
|
errorCallback=self.output.writeStdErr,
|
|
182
|
-
terminateCallback=self.
|
|
200
|
+
terminateCallback=self.onUninstallExit
|
|
183
201
|
)
|
|
184
|
-
self.pipProcess.start()
|
|
202
|
+
self.pipProcess.start(env=env)
|
|
203
|
+
|
|
204
|
+
global NEEDS_RESTART # flag as needing a restart
|
|
205
|
+
NEEDS_RESTART = True
|
|
185
206
|
|
|
186
207
|
def installPackage(self, packageName, version=None, extra=None):
|
|
187
208
|
"""Install a package.
|
|
@@ -222,25 +243,8 @@ class EnvironmentManagerDlg(wx.Dialog):
|
|
|
222
243
|
|
|
223
244
|
# interpreter path
|
|
224
245
|
pyExec = sys.executable
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
if sys.platform == "darwin":
|
|
228
|
-
# determine installation path for bundle, create it if needed
|
|
229
|
-
bundlePath = plugins.getBundleInstallTarget(packageName)
|
|
230
|
-
if not os.path.exists(bundlePath):
|
|
231
|
-
self.output.writeStdOut(
|
|
232
|
-
"Creating bundle path `{}` for package `{}`.".format(
|
|
233
|
-
bundlePath, packageName))
|
|
234
|
-
os.mkdir(bundlePath) # make the directory
|
|
235
|
-
else:
|
|
236
|
-
self.output.writeStdOut(
|
|
237
|
-
"Using existing bundle path `{}` for package `{}`.".format(
|
|
238
|
-
bundlePath, packageName))
|
|
239
|
-
|
|
240
|
-
# add the bundle to path, refresh makes it discoverable after install
|
|
241
|
-
if bundlePath not in sys.path:
|
|
242
|
-
sys.path.insert(0, bundlePath)
|
|
243
|
-
|
|
246
|
+
# environment
|
|
247
|
+
env = os.environ.copy()
|
|
244
248
|
# if given a pyproject.toml file, do editable install of parent folder
|
|
245
249
|
if str(packageName).endswith("pyproject.toml"):
|
|
246
250
|
if sys.platform != "darwin":
|
|
@@ -250,7 +254,8 @@ class EnvironmentManagerDlg(wx.Dialog):
|
|
|
250
254
|
# on Mac, build a wheel
|
|
251
255
|
subprocess.call(
|
|
252
256
|
[pyExec, '-m', 'build'],
|
|
253
|
-
cwd=Path(packageName).parent
|
|
257
|
+
cwd=Path(packageName).parent,
|
|
258
|
+
env=env
|
|
254
259
|
)
|
|
255
260
|
# get wheel path
|
|
256
261
|
packageName = [
|
|
@@ -259,16 +264,23 @@ class EnvironmentManagerDlg(wx.Dialog):
|
|
|
259
264
|
# On MacOS, we need to install to target instead of user since py2app
|
|
260
265
|
# doesn't support user installs correctly, this is a workaround for that
|
|
261
266
|
env = os.environ.copy()
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
267
|
+
|
|
268
|
+
# build the shell command to run the script
|
|
269
|
+
command = [pyExec, '-m', 'pip', 'install', str(packageName)]
|
|
270
|
+
|
|
271
|
+
# check if we are inside a venv, don't use --user if we are
|
|
272
|
+
if hasattr(sys, 'real_prefix') or (
|
|
273
|
+
hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix):
|
|
274
|
+
# we are in a venv
|
|
275
|
+
logging.warning(
|
|
276
|
+
"You are installing a package inside a virtual environment. "
|
|
277
|
+
"The package will be installed in the user site-packages directory."
|
|
278
|
+
)
|
|
268
279
|
else:
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
280
|
+
command.append('--user')
|
|
281
|
+
|
|
282
|
+
# add other options to the command
|
|
283
|
+
command += ['--prefer-binary', '--no-input', '--no-color']
|
|
272
284
|
|
|
273
285
|
# write command to output panel
|
|
274
286
|
self.output.writeCmd(" ".join(command))
|
|
@@ -311,6 +323,7 @@ class EnvironmentManagerDlg(wx.Dialog):
|
|
|
311
323
|
will be installed.
|
|
312
324
|
|
|
313
325
|
"""
|
|
326
|
+
# do install
|
|
314
327
|
self.installPackage(
|
|
315
328
|
packageName=pluginInfo.pipname,
|
|
316
329
|
version=version,
|
|
@@ -319,6 +332,21 @@ class EnvironmentManagerDlg(wx.Dialog):
|
|
|
319
332
|
}
|
|
320
333
|
)
|
|
321
334
|
|
|
335
|
+
def uninstallPlugin(self, pluginInfo):
|
|
336
|
+
"""Uninstall a plugin.
|
|
337
|
+
|
|
338
|
+
This deletes any bundles in the user's package directory, or uninstalls
|
|
339
|
+
packages from `site-packages`.
|
|
340
|
+
|
|
341
|
+
Parameters
|
|
342
|
+
----------
|
|
343
|
+
pluginInfo : psychopy.app.plugin_manager.plugins.PluginInfo
|
|
344
|
+
Info object of the plugin to uninstall.
|
|
345
|
+
|
|
346
|
+
"""
|
|
347
|
+
# do uninstall
|
|
348
|
+
self.uninstallPackage(pluginInfo.pipname)
|
|
349
|
+
|
|
322
350
|
def onInstallExit(self, pid, exitCode):
|
|
323
351
|
"""
|
|
324
352
|
Callback function to handle a pip process exiting. Prints a termination statement
|
|
@@ -328,7 +356,6 @@ class EnvironmentManagerDlg(wx.Dialog):
|
|
|
328
356
|
if self.pipProcess is None:
|
|
329
357
|
# if pip process is None, this has been called by mistake, do nothing
|
|
330
358
|
return
|
|
331
|
-
|
|
332
359
|
# write installation termination statement
|
|
333
360
|
msg = "Installation complete"
|
|
334
361
|
if 'pipname' in self.pipProcess.extra:
|
|
@@ -344,12 +371,17 @@ class EnvironmentManagerDlg(wx.Dialog):
|
|
|
344
371
|
# enable plugin
|
|
345
372
|
try:
|
|
346
373
|
pluginInfo.activate()
|
|
347
|
-
plugins.loadPlugin(pluginInfo.pipname)
|
|
374
|
+
# plugins.loadPlugin(pluginInfo.pipname)
|
|
348
375
|
except RuntimeError:
|
|
349
376
|
prefs.general['startUpPlugins'].append(pluginInfo.pipname)
|
|
350
377
|
self.output.writeStdErr(_translate(
|
|
351
378
|
"[Warning] Could not activate plugin. PsychoPy may need to restart for plugin to take effect."
|
|
352
379
|
))
|
|
380
|
+
|
|
381
|
+
global NEEDS_RESTART # flag as needing a restart
|
|
382
|
+
NEEDS_RESTART = True
|
|
383
|
+
showNeedsRestartDialog()
|
|
384
|
+
|
|
353
385
|
# show list of components/routines now available
|
|
354
386
|
emts = []
|
|
355
387
|
for name, emt in getAllElements().items():
|
|
@@ -376,25 +408,46 @@ class EnvironmentManagerDlg(wx.Dialog):
|
|
|
376
408
|
|
|
377
409
|
# clear pip process
|
|
378
410
|
self.pipProcess = None
|
|
411
|
+
# refresh view
|
|
412
|
+
pkgtools.refreshPackages()
|
|
413
|
+
self.pluginMgr.updateInfo()
|
|
414
|
+
|
|
415
|
+
def onUninstallExit(self, pid, exitCode):
|
|
416
|
+
# write installation termination statement
|
|
417
|
+
msg = "Uninstall complete"
|
|
418
|
+
if 'pipname' in self.pipProcess.extra:
|
|
419
|
+
msg = f"Finished uninstalling %(pipname)s" % self.pipProcess.extra
|
|
420
|
+
self.output.writeTerminus(msg)
|
|
421
|
+
# clear pip process
|
|
422
|
+
self.pipProcess = None
|
|
379
423
|
|
|
380
424
|
def onClose(self, evt=None):
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
# If any plugins have been uninstalled, prompt user to restart
|
|
385
|
-
if any(["uninstalled" in changes for changes in pluginChanges.values()]):
|
|
386
|
-
msg = _translate(
|
|
387
|
-
"It looks like you've uninstalled some plugins. In order for this to take effect, you will need to "
|
|
388
|
-
"restart the PsychoPy app."
|
|
389
|
-
)
|
|
425
|
+
if self.isBusy:
|
|
426
|
+
# if closing during an install, prompt user to reconsider
|
|
390
427
|
dlg = wx.MessageDialog(
|
|
391
|
-
|
|
392
|
-
|
|
428
|
+
self,
|
|
429
|
+
_translate(
|
|
430
|
+
"There is currently an installation/uninstallation in progress, are you sure "
|
|
431
|
+
"you want to close?"
|
|
432
|
+
),
|
|
433
|
+
style=wx.YES | wx.NO
|
|
393
434
|
)
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
435
|
+
# if they change their mind, cancel closing
|
|
436
|
+
if dlg.ShowModal() == wx.ID_NO:
|
|
437
|
+
return
|
|
438
|
+
|
|
439
|
+
if evt is not None:
|
|
440
|
+
evt.Skip()
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def showNeedsRestartDialog():
|
|
444
|
+
"""Show a dialog asking the user if they would like to restart PsychoPy.
|
|
445
|
+
"""
|
|
446
|
+
msg = _translate("Please restart PsychoPy to apply changes.")
|
|
447
|
+
|
|
448
|
+
# show a simple dialog that asks the user to restart PsychoPy
|
|
449
|
+
dlg = wx.MessageDialog(
|
|
450
|
+
None, msg, "Restart Required",
|
|
451
|
+
style=wx.ICON_INFORMATION | wx.OK
|
|
452
|
+
)
|
|
453
|
+
dlg.ShowModal()
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import webbrowser
|
|
2
2
|
|
|
3
3
|
import wx
|
|
4
|
+
import os
|
|
4
5
|
import sys
|
|
5
6
|
import subprocess as sp
|
|
6
7
|
from pypi_search import search as pypi
|
|
@@ -101,11 +102,15 @@ class PIPTerminalPanel(wx.Panel):
|
|
|
101
102
|
|
|
102
103
|
def runCommand(self, cmd):
|
|
103
104
|
"""Run the command."""
|
|
105
|
+
|
|
106
|
+
env = os.environ.copy()
|
|
107
|
+
|
|
104
108
|
emts = [self.preface, cmd]
|
|
105
109
|
output = sp.Popen(' '.join(emts),
|
|
106
110
|
stdout=sp.PIPE,
|
|
107
111
|
stderr=sp.PIPE,
|
|
108
112
|
shell=True,
|
|
113
|
+
env=env,
|
|
109
114
|
universal_newlines=True)
|
|
110
115
|
stdout, stderr = output.communicate()
|
|
111
116
|
sys.stdout.write(stdout)
|