2626
2727# Third party imports (qtpy)
2828from qtpy .QtCore import QUrl , QTimer , Signal , Slot
29- from qtpy .QtWidgets import QApplication , QVBoxLayout , QWidget
29+ from qtpy .QtWidgets import QApplication , QMessageBox , QVBoxLayout , QWidget
3030
3131# Local imports
3232from spyder .api .asyncdispatcher import AsyncDispatcher
4343from spyder .utils .qthelpers import DialogManager
4444from spyder .plugins .ipythonconsole import (
4545 SpyderKernelError ,
46- SpyderKernelVersionError ,
46+ SPYDER_KERNELS_VERSION ,
4747)
4848from spyder .plugins .ipythonconsole .utils .kernel_handler import (
4949 KernelConnectionState ,
5050 KernelHandler
5151)
5252from spyder .plugins .ipythonconsole .widgets import ShellWidget
53+ from spyder .plugins .ipythonconsole .widgets .install_spyder_kernels import (
54+ SpyderKernelInstallWidget ,
55+ INSTALL_TEXT ,
56+ )
5357from spyder .widgets .collectionseditor import CollectionsEditor
5458from spyder .widgets .mixins import SaveHistoryMixin
55- from spyder .plugins .ipythonconsole .widgets import SpyderKernelInstallWidget
5659
5760if typing .TYPE_CHECKING :
5861 from spyder .plugins .remoteclient .api .modules import JupyterAPI
@@ -175,7 +178,8 @@ def __init__(
175178 self .infowidget = self .container .infowidget
176179 self .blank_page = self ._create_blank_page ()
177180 self .kernel_loading_page = self ._create_loading_page ()
178- self .env_loading_page = self ._create_loading_page (env = True )
181+ self .env_loading_page = self ._create_loading_page (kind = "env" )
182+ self .spyk_installing_page = self ._create_loading_page (kind = "install" )
179183
180184 if self .is_remote ():
181185 # Keep a reference
@@ -207,6 +211,15 @@ def __init__(
207211 self .__remote_restart_requested = False
208212 self .__remote_reconnect_requested = False
209213
214+ # --- Install spyder-kernels message box
215+ self .install_mbox = QMessageBox (self )
216+ self .install_mbox .setIcon (QMessageBox .Icon .Question )
217+ self .install_mbox .setWindowTitle (self .container ._plugin .get_name ())
218+ self .install_mbox .setStandardButtons (
219+ QMessageBox .Yes | QMessageBox .Cancel
220+ )
221+ self .install_mbox .button (QMessageBox .Yes ).setText (_ ("Install" ))
222+
210223 # ---- Private methods
211224 # -------------------------------------------------------------------------
212225 def _when_kernel_is_ready (self ):
@@ -245,16 +258,20 @@ def _when_kernel_is_ready(self):
245258 if self .give_focus :
246259 self .shellwidget ._control .setFocus ()
247260
248- def _create_loading_page (self , env = False ):
261+ def _create_loading_page (self , kind = None ):
249262 """Create html page to show while the kernel is starting"""
250263 loading_template = Template (LOADING )
251264 loading_img = get_image_path ('loading_sprites' )
252265 if os .name == 'nt' :
253266 loading_img = loading_img .replace ('\\ ' , '/' )
254- message = _ ("Connecting to kernel..." )
255267
256- if env :
268+ if kind is None :
269+ message = _ ("Connecting to kernel..." )
270+ elif kind == "env" :
257271 message = _ ("Retrieving environment variables..." )
272+ elif kind == "install" :
273+ message = _ ("Installing spyder-kernels..." )
274+
258275 page = loading_template .substitute (
259276 css_path = self .css_path ,
260277 loading_img = loading_img ,
@@ -385,8 +402,35 @@ def _set_initial_cwd_in_kernel(self):
385402 cwd_path , emit_cwd_change = emit_cwd_change
386403 )
387404
405+ @Slot ()
406+ def _install_spyder_kernels (self , pyexec ):
407+ # TODO: Disable create new client with same environment
408+
409+ # Store existing error page for reuse later, if necessary
410+ self .installwidget .info_page = self .info_page
411+
412+ self ._show_loading_page (self .spyk_installing_page )
413+ self .installwidget .show ()
414+
415+ # Install spyder kernels...
416+ self .installwidget .install_spyder_kernels (pyexec )
417+
388418 # ---- Public API
389419 # -------------------------------------------------------------------------
420+ def show_install_mbox (self , pyexec ):
421+ self .install_mbox .setText (
422+ INSTALL_TEXT .format (
423+ SPYDER_KERNELS_VERSION .replace (">" , ">" ).replace (
424+ "<" , "<"
425+ ),
426+ pyexec ,
427+ ),
428+ )
429+ self .install_mbox .accepted .connect (
430+ functools .partial (self ._install_spyder_kernels , pyexec )
431+ )
432+ self .install_mbox .show ()
433+
390434 @property
391435 def connection_file (self ):
392436 if self .kernel_handler is None :
@@ -517,22 +561,29 @@ def stop_button_click_handler(self):
517561 else :
518562 self .shellwidget .pdb_execute_command ('exit' )
519563
520- def show_kernel_install (self ):
521- self ._hide_loading_page ()
522- self .shellwidget .hide ()
523- self .installwidget .show ()
524-
525- def connect_after_kernel_install (self ):
526- self ._show_loading_page (self .env_loading_page )
527- self .sig_connect_after_kernel_install .emit ()
564+ def process_kernel_install (self , exit_code , exit_status , output = None ):
565+ # TODO: Re-enable create new client with same environment
566+
567+ if exit_code == 0 and exit_status == 0 :
568+ # Success!
569+ self ._show_loading_page (self .env_loading_page )
570+ self .sig_connect_after_kernel_install .emit ()
571+ elif exit_code == 15 and exit_status == 1 :
572+ # Cancelled by user, just display previous kernel error page
573+ self ._show_loading_page (self .installwidget .info_page )
574+ elif exit_code != 0 and exit_status == 0 :
575+ # An error occurred during install
576+ self .show_kernel_error (f"<tt>{ output } </tt>" , install = True )
577+ else :
578+ # Unknown error
579+ logger .info (
580+ "Unknown installer error. "
581+ f"Exit code: { exit_code } ; exit status: { exit_status } "
582+ )
528583
529- def show_kernel_error (self , error ):
584+ def show_kernel_error (self , error , install = False ):
530585 """Show kernel initialization errors in infowidget."""
531- if isinstance (error , SpyderKernelVersionError ):
532- self .installwidget .kernel_error = error
533- self .show_kernel_install ()
534- return
535- elif isinstance (error , SpyderKernelError ):
586+ if isinstance (error , SpyderKernelError ):
536587 error = error .args [0 ]
537588 elif isinstance (error , Exception ):
538589 error = _ ("The error is:<br><br>"
@@ -557,7 +608,10 @@ def show_kernel_error(self, error):
557608 error = error .replace ('-' , '‑' )
558609
559610 # Create error page
560- message = _ ("An error occurred while starting the kernel" )
611+ if install :
612+ message = _ ("An error occurred while installing spyder-kernls" )
613+ else :
614+ message = _ ("An error occurred while starting the kernel" )
561615 kernel_error_template = Template (KERNEL_ERROR )
562616 self .info_page = kernel_error_template .substitute (
563617 css_path = self .css_path ,
@@ -680,6 +734,7 @@ def set_color_scheme(self, color_scheme, reset=True):
680734
681735 def close_client (self , is_last_client , close_console = False ):
682736 """Close the client."""
737+ self .install_mbox .reject ()
683738 self .__on_close = lambda : None
684739 debugging = False
685740
0 commit comments