@@ -3061,6 +3061,72 @@ def start_app(self) -> None:
30613061 )
30623062 self .exit (1 )
30633063
3064+ self .write_server_info_file ()
3065+
3066+ if not self .no_browser_open_file :
3067+ self .write_browser_open_files ()
3068+
3069+ # Handle the browser opening.
3070+ if self .open_browser and not self .sock :
3071+ self .launch_browser ()
3072+
3073+ async def _cleanup (self ) -> None :
3074+ """General cleanup of files, extensions and kernels created
3075+ by this instance ServerApp.
3076+ """
3077+ self .remove_server_info_file ()
3078+ self .remove_browser_open_files ()
3079+ await self .cleanup_extensions ()
3080+ await self .cleanup_kernels ()
3081+ try :
3082+ await self .kernel_websocket_connection_class .close_all () # type:ignore[attr-defined]
3083+ except AttributeError :
3084+ # This can happen in two different scenarios:
3085+ #
3086+ # 1. During tests, where the _cleanup method is invoked without
3087+ # the corresponding initialize method having been invoked.
3088+ # 2. If the provided `kernel_websocket_connection_class` does not
3089+ # implement the `close_all` class method.
3090+ #
3091+ # In either case, we don't need to do anything and just want to treat
3092+ # the raised error as a no-op.
3093+ pass
3094+ if getattr (self , "kernel_manager" , None ):
3095+ self .kernel_manager .__del__ ()
3096+ if getattr (self , "session_manager" , None ):
3097+ self .session_manager .close ()
3098+ if hasattr (self , "http_server" ):
3099+ # Stop a server if its set.
3100+ self .http_server .stop ()
3101+
3102+ def start_ioloop (self ) -> None :
3103+ """Start the IO Loop."""
3104+ if sys .platform .startswith ("win" ):
3105+ # add no-op to wake every 5s
3106+ # to handle signals that may be ignored by the inner loop
3107+ pc = ioloop .PeriodicCallback (lambda : None , 5000 )
3108+ pc .start ()
3109+ try :
3110+ self .io_loop .add_callback (self ._post_start )
3111+ self .io_loop .start ()
3112+ except KeyboardInterrupt :
3113+ self .log .info (_i18n ("Interrupted..." ))
3114+
3115+ def init_ioloop (self ) -> None :
3116+ """init self.io_loop so that an extension can use it by io_loop.call_later() to create background tasks"""
3117+ self .io_loop = ioloop .IOLoop .current ()
3118+
3119+ async def _post_start (self ):
3120+ """Add an async hook to start tasks after the event loop is running.
3121+
3122+ This will also attempt to start all tasks found in
3123+ the `start_extension` method in Extension Apps.
3124+ """
3125+ try :
3126+ await self .extension_manager .start_all_extensions ()
3127+ except Exception as err :
3128+ self .log .error (err )
3129+
30643130 info = self .log .info
30653131 for line in self .running_server_info (kernel_count = False ).split ("\n " ):
30663132 info (line )
@@ -3079,15 +3145,6 @@ def start_app(self) -> None:
30793145 )
30803146 )
30813147
3082- self .write_server_info_file ()
3083-
3084- if not self .no_browser_open_file :
3085- self .write_browser_open_files ()
3086-
3087- # Handle the browser opening.
3088- if self .open_browser and not self .sock :
3089- self .launch_browser ()
3090-
30913148 if self .identity_provider .token and self .identity_provider .token_generated :
30923149 # log full URL with generated token, so there's a copy/pasteable link
30933150 # with auth info.
@@ -3128,51 +3185,6 @@ def start_app(self) -> None:
31283185
31293186 self .log .critical ("\n " .join (message ))
31303187
3131- async def _cleanup (self ) -> None :
3132- """General cleanup of files, extensions and kernels created
3133- by this instance ServerApp.
3134- """
3135- self .remove_server_info_file ()
3136- self .remove_browser_open_files ()
3137- await self .cleanup_extensions ()
3138- await self .cleanup_kernels ()
3139- try :
3140- await self .kernel_websocket_connection_class .close_all () # type:ignore[attr-defined]
3141- except AttributeError :
3142- # This can happen in two different scenarios:
3143- #
3144- # 1. During tests, where the _cleanup method is invoked without
3145- # the corresponding initialize method having been invoked.
3146- # 2. If the provided `kernel_websocket_connection_class` does not
3147- # implement the `close_all` class method.
3148- #
3149- # In either case, we don't need to do anything and just want to treat
3150- # the raised error as a no-op.
3151- pass
3152- if getattr (self , "kernel_manager" , None ):
3153- self .kernel_manager .__del__ ()
3154- if getattr (self , "session_manager" , None ):
3155- self .session_manager .close ()
3156- if hasattr (self , "http_server" ):
3157- # Stop a server if its set.
3158- self .http_server .stop ()
3159-
3160- def start_ioloop (self ) -> None :
3161- """Start the IO Loop."""
3162- if sys .platform .startswith ("win" ):
3163- # add no-op to wake every 5s
3164- # to handle signals that may be ignored by the inner loop
3165- pc = ioloop .PeriodicCallback (lambda : None , 5000 )
3166- pc .start ()
3167- try :
3168- self .io_loop .start ()
3169- except KeyboardInterrupt :
3170- self .log .info (_i18n ("Interrupted..." ))
3171-
3172- def init_ioloop (self ) -> None :
3173- """init self.io_loop so that an extension can use it by io_loop.call_later() to create background tasks"""
3174- self .io_loop = ioloop .IOLoop .current ()
3175-
31763188 def start (self ) -> None :
31773189 """Start the Jupyter server app, after initialization
31783190
0 commit comments