@@ -3061,6 +3061,72 @@ def start_app(self) -> None:
3061
3061
)
3062
3062
self .exit (1 )
3063
3063
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
+
3064
3130
info = self .log .info
3065
3131
for line in self .running_server_info (kernel_count = False ).split ("\n " ):
3066
3132
info (line )
@@ -3079,15 +3145,6 @@ def start_app(self) -> None:
3079
3145
)
3080
3146
)
3081
3147
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
-
3091
3148
if self .identity_provider .token and self .identity_provider .token_generated :
3092
3149
# log full URL with generated token, so there's a copy/pasteable link
3093
3150
# with auth info.
@@ -3128,51 +3185,6 @@ def start_app(self) -> None:
3128
3185
3129
3186
self .log .critical ("\n " .join (message ))
3130
3187
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
-
3176
3188
def start (self ) -> None :
3177
3189
"""Start the Jupyter server app, after initialization
3178
3190
0 commit comments