@@ -2999,6 +2999,72 @@ def start_app(self) -> None:
29992999 )
30003000 self .exit (1 )
30013001
3002+ self .write_server_info_file ()
3003+
3004+ if not self .no_browser_open_file :
3005+ self .write_browser_open_files ()
3006+
3007+ # Handle the browser opening.
3008+ if self .open_browser and not self .sock :
3009+ self .launch_browser ()
3010+
3011+ async def _cleanup (self ) -> None :
3012+ """General cleanup of files, extensions and kernels created
3013+ by this instance ServerApp.
3014+ """
3015+ self .remove_server_info_file ()
3016+ self .remove_browser_open_files ()
3017+ await self .cleanup_extensions ()
3018+ await self .cleanup_kernels ()
3019+ try :
3020+ await self .kernel_websocket_connection_class .close_all () # type:ignore[attr-defined]
3021+ except AttributeError :
3022+ # This can happen in two different scenarios:
3023+ #
3024+ # 1. During tests, where the _cleanup method is invoked without
3025+ # the corresponding initialize method having been invoked.
3026+ # 2. If the provided `kernel_websocket_connection_class` does not
3027+ # implement the `close_all` class method.
3028+ #
3029+ # In either case, we don't need to do anything and just want to treat
3030+ # the raised error as a no-op.
3031+ pass
3032+ if getattr (self , "kernel_manager" , None ):
3033+ self .kernel_manager .__del__ ()
3034+ if getattr (self , "session_manager" , None ):
3035+ self .session_manager .close ()
3036+ if hasattr (self , "http_server" ):
3037+ # Stop a server if its set.
3038+ self .http_server .stop ()
3039+
3040+ def start_ioloop (self ) -> None :
3041+ """Start the IO Loop."""
3042+ if sys .platform .startswith ("win" ):
3043+ # add no-op to wake every 5s
3044+ # to handle signals that may be ignored by the inner loop
3045+ pc = ioloop .PeriodicCallback (lambda : None , 5000 )
3046+ pc .start ()
3047+ try :
3048+ self .io_loop .add_callback (self ._post_start )
3049+ self .io_loop .start ()
3050+ except KeyboardInterrupt :
3051+ self .log .info (_i18n ("Interrupted..." ))
3052+
3053+ def init_ioloop (self ) -> None :
3054+ """init self.io_loop so that an extension can use it by io_loop.call_later() to create background tasks"""
3055+ self .io_loop = ioloop .IOLoop .current ()
3056+
3057+ async def _post_start (self ):
3058+ """Add an async hook to start tasks after the event loop is running.
3059+
3060+ This will also attempt to start all tasks found in
3061+ the `start_extension` method in Extension Apps.
3062+ """
3063+ try :
3064+ await self .extension_manager .start_all_extensions ()
3065+ except Exception as err :
3066+ self .log .error (err )
3067+
30023068 info = self .log .info
30033069 for line in self .running_server_info (kernel_count = False ).split ("\n " ):
30043070 info (line )
@@ -3017,15 +3083,6 @@ def start_app(self) -> None:
30173083 )
30183084 )
30193085
3020- self .write_server_info_file ()
3021-
3022- if not self .no_browser_open_file :
3023- self .write_browser_open_files ()
3024-
3025- # Handle the browser opening.
3026- if self .open_browser and not self .sock :
3027- self .launch_browser ()
3028-
30293086 if self .identity_provider .token and self .identity_provider .token_generated :
30303087 # log full URL with generated token, so there's a copy/pasteable link
30313088 # with auth info.
@@ -3066,51 +3123,6 @@ def start_app(self) -> None:
30663123
30673124 self .log .critical ("\n " .join (message ))
30683125
3069- async def _cleanup (self ) -> None :
3070- """General cleanup of files, extensions and kernels created
3071- by this instance ServerApp.
3072- """
3073- self .remove_server_info_file ()
3074- self .remove_browser_open_files ()
3075- await self .cleanup_extensions ()
3076- await self .cleanup_kernels ()
3077- try :
3078- await self .kernel_websocket_connection_class .close_all () # type:ignore[attr-defined]
3079- except AttributeError :
3080- # This can happen in two different scenarios:
3081- #
3082- # 1. During tests, where the _cleanup method is invoked without
3083- # the corresponding initialize method having been invoked.
3084- # 2. If the provided `kernel_websocket_connection_class` does not
3085- # implement the `close_all` class method.
3086- #
3087- # In either case, we don't need to do anything and just want to treat
3088- # the raised error as a no-op.
3089- pass
3090- if getattr (self , "kernel_manager" , None ):
3091- self .kernel_manager .__del__ ()
3092- if getattr (self , "session_manager" , None ):
3093- self .session_manager .close ()
3094- if hasattr (self , "http_server" ):
3095- # Stop a server if its set.
3096- self .http_server .stop ()
3097-
3098- def start_ioloop (self ) -> None :
3099- """Start the IO Loop."""
3100- if sys .platform .startswith ("win" ):
3101- # add no-op to wake every 5s
3102- # to handle signals that may be ignored by the inner loop
3103- pc = ioloop .PeriodicCallback (lambda : None , 5000 )
3104- pc .start ()
3105- try :
3106- self .io_loop .start ()
3107- except KeyboardInterrupt :
3108- self .log .info (_i18n ("Interrupted..." ))
3109-
3110- def init_ioloop (self ) -> None :
3111- """init self.io_loop so that an extension can use it by io_loop.call_later() to create background tasks"""
3112- self .io_loop = ioloop .IOLoop .current ()
3113-
31143126 def start (self ) -> None :
31153127 """Start the Jupyter server app, after initialization
31163128
0 commit comments