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