Procházet zdrojové kódy

Clean up documentation and api for session context

Jason Grout před 5 roky
rodič
revize
cc192f0c90

+ 42 - 105
packages/apputils/src/sessioncontext.tsx

@@ -28,79 +28,15 @@ import { showDialog, Dialog } from './dialog';
 import { KernelSpec } from '@jupyterlab/services/lib/kernelspec';
 
 /**
- * The interface of client session object.
+ * A context object to manage a widget's kernel session connection.
  *
- * OLD: The client session represents the link between a path and its kernel
- * for the duration of the lifetime of the session object.  The session can
- * have no current kernel, and can start a new kernel at any time.
- *
- * NEW: A client session represents a single object that proxies the session
- * information for the session an object is connected to. This is a
- * convenience object that points to a specific session (which in turn points
- * to a specific kernel). The signals here are proxied from the current
- * kernel.
- *
- * For any session-specific operations, use the .session attribute. For any
- * kernel-specific things, use .session.kernel. For convenience, we proxy the
- * current kernel and session signals to the client session (so you don't have
- * to handle session or kernel changes in your slots).
- *
- * A session represents a persistent resource to address a kernel. The kernel
- * can be restarted or changed.
- *
- * A clientSession represents a client-side handle to a single session.
- * Essentially, the main thing it adds is a sessionChanged signal, which
- * represents pointing your clientSession to a different session.
- *
- * For example, a variable explorer contains a clientSession. That points the
- * current session the variable explorer is hooked to, and gives notifications
- * when changing sessions. The clientSession object on the variable explorer
- * is a single object whose lifecycle matches the variable explorer widget.
- * The session object matches the persistent
- *
- * A kernel represents a computational process. Its lifecycle is determined by
- * explicit restarts and shutdowns, computational conditions (such as OOM
- * errors), etc.
- *
- * A session represents a connection to semantic kernel. It is initiated
- * explicitly, and persists beyond kernel shutdowns, and provides a single
- * handle for multiple activities talking to the same computational resource
- * kernel (even if that kernel is restarted or changed). For example, a
- * console and a notebook can point to the same session, which means they will
- * continue pointing to the same kernel even if the session's kernel is
- * switched. Sessions are stored on the server side in the rest API.
- *
- * A clientSession represents a mapping of a widget to a session. Its
- * lifecycle is the widget lifecycle.
- *
- * A plugin for a widget would grab the widget's clientSession to have a
- * persistent handle on whatever computation resource was tied to the widget.
- * The session a clientSession points to may be restored as part of the widget
- * restoration process (so refreshing a page will point the widget to the
- * right session). The Running tab UI should provide a way to point a widget's
- * clientSession to a new session. It should also provide a way to explicitly
- * manage the kernel associated with the session (restart, change, interrupt,
- * etc.).
- *
- * For many things, we only care about kernel signals from the current kernel,
- * no matter how many times the session or kernel changes. Since it is
- * inconvenient to disconnect and connect handlers every time a session or
- * kernel changes, we proxy the kernel signals to the session, and the session
- * signals to the clientSession. So to act on whatever the current kernel's
- * iopubmessage signal, just hook up to the clientSession's iopubmessage
- * signal.
- *
- * Another possibility would be to offer a utility function to
- * connect/disconnect a specific function on a signal. Use one signal to
- * affect the connection/disconnection of another signal. For example, given a
- * change signal and a slot and an initial object, on any change signal, it
- * would disconnect the slot from the old value and connect it to the new
- * value.
- *
- * To manage a kernel lifecycle, you can change the kernel for a session
- * (which affects all connections to that session), or you can create a
- * connection to a new session (which does not affect other connections to a
- * session).
+ * #### Notes
+ * The current session connection is `.session`, the current session's kernel
+ * connection is `.session.kernel`. For convenience, we proxy several kernel
+ * connection and and session connection signals up to the session context so
+ * that you do not have to manage slots as sessions and kernels change. For
+ * example, to act on whatever the current kernel's iopubMessage signal is
+ * producing, connect to the session context `.iopubMessage` signal.
  *
  */
 export interface ISessionContext extends IObservableDisposable {
@@ -165,13 +101,6 @@ export interface ISessionContext extends IObservableDisposable {
    */
   readonly kernelDisplayName: string;
 
-  /**
-   * Change the current kernel associated with the document.
-   *
-   * TODO: this currently changes a kernel if the session exists, otherwise
-   * starts a new session, so it is kind of a shorthand convenience function.
-   */
-
   /**
    * Kill the kernel and shutdown the session.
    *
@@ -182,31 +111,31 @@ export interface ISessionContext extends IObservableDisposable {
   /**
    * Use a UX to select a new kernel for the session.
    *
-   * TODO: should this select a new kernel for the session, or make a new session?
-   *
-   * TODO: Make this function an optional constructor option, so that we can customize it.
+   * TODO: make this function an optional constructor option so we can easily customize the UX
    */
   selectKernel(): Promise<void>;
 
   /**
-   * Restart the session.
+   * Restart the kernel, with confirmation UX.
    *
    * @returns A promise that resolves with whether the kernel has restarted.
    *
    * #### Notes
-   * The purpose here is to make it easy to get a new kernel running in a
-   * session when we once had a kernel running.
+   * This method makes it easy to get a new kernel running in a session where
+   * we used to have a session running.
+   *
+   * * If there is a running kernel, present a confirmation dialog.
+   * * If there is no kernel, start a kernel with the last-run kernel name.
+   * * If no kernel has ever been started, this is a no-op, and resolves with
+   *   `false`.
+   *
+   * TODO: be able to pass in a factory for the restart dialog so we can
+   * override the default.
    *
    * TODO: We keep the last kernel that this session ran here, in case the
    * session lifetime is tied to the kernel lifetime.
    *
-   * * If there is a running kernel, present a dialog.
-   * * If there is no kernel, we start a kernel with the last run kernel name
-   *   and resolves with `true`.
-   * * If no kernel has been started, this is a no-op, and resolves with
-   *   `false`.
-   *
-   * TODO: be able to pass in a factory for the restart dialog so we can override the default.
+   * TODO: perhaps if there wasn't a kernel in memory, call out to selectKernel?
    */
   restart(): Promise<boolean>;
 }
@@ -217,6 +146,11 @@ export interface ISessionContext extends IObservableDisposable {
 export namespace ISessionContext {
   /**
    * A kernel preference.
+   *
+   * #### Notes
+   * Preferences for a kernel are considered in the order `id`, `name`,
+   * `language`. If no matching kernels can be found and `autoStartDefault` is
+   * `true`, then the default kernel for the server is preferred.
    */
   export interface IKernelPreference {
     /**
@@ -235,22 +169,23 @@ export namespace ISessionContext {
     readonly id?: string;
 
     /**
-     * Whether to prefer starting a kernel.
+     * A kernel should be started automatically (default `true`).
      */
     readonly shouldStart?: boolean;
 
     /**
-     * Whether a kernel can be started.
+     * A kernel can be started (default `true`).
      */
     readonly canStart?: boolean;
 
     /**
-     * Whether a kernel needs to be close with the associated session
+     * Shut down the session when session context is disposed (default `false`).
      */
-    readonly shutdownOnClose?: boolean;
+    readonly shutdownOnDispose?: boolean;
 
     /**
-     * Whether to auto-start the default kernel if no matching kernel is found.
+     * Automatically start the default kernel if no other matching kernel is
+     * found (default `true`).
      */
     readonly autoStartDefault?: boolean;
   }
@@ -264,13 +199,13 @@ export class SessionContext implements ISessionContext {
    * Construct a new client session.
    */
   constructor(options: SessionContext.IOptions) {
-    this.manager = options.manager;
+    this.manager = options.sessionManager;
     this.specsManager = options.specsManager;
-    this._path = options.path || UUID.uuid4();
-    this._type = options.type || '';
-    this._name = options.name || '';
+    this._path = options.path ?? UUID.uuid4();
+    this._type = options.type ?? '';
+    this._name = options.name ?? '';
     this._setBusy = options.setBusy;
-    this._kernelPreference = options.kernelPreference || {};
+    this._kernelPreference = options.kernelPreference ?? {};
   }
 
   /**
@@ -395,7 +330,7 @@ export class SessionContext implements ISessionContext {
     }
     this._isDisposed = true;
     if (this._session) {
-      if (this.kernelPreference.shutdownOnClose) {
+      if (this.kernelPreference.shutdownOnDispose) {
         // Fire and forget the session shutdown request
         this._session.shutdown().catch(reason => {
           console.error(`Kernel not shut down ${reason}`);
@@ -840,13 +775,15 @@ export namespace SessionContext {
     /**
      * A session manager instance.
      */
-    manager: Session.IManager;
+    sessionManager: Session.IManager;
 
     /**
-     * A manager for kernel specs
+     * A kernel spec manager instance.
      */
     specsManager: KernelSpec.IManager;
 
+    // TODO: Should we just accept a Partial<Session.IModel>?
+
     /**
      * The initial path of the file.
      */

+ 1 - 1
packages/apputils/src/toolbar.tsx

@@ -17,7 +17,7 @@ import { AttachedProperty } from '@phosphor/properties';
 
 import { PanelLayout, Widget } from '@phosphor/widgets';
 
-import { ISessionContext } from './clientsession';
+import { ISessionContext } from './sessioncontext';
 
 import * as React from 'react';
 import { ReadonlyJSONObject } from '@phosphor/coreutils';

+ 1 - 1
packages/console/src/panel.ts

@@ -59,7 +59,7 @@ export class ConsolePanel extends Panel {
     }
 
     let sessionContext = (this._sessionContext = new SessionContext({
-      manager: manager.sessions,
+      sessionManager: manager.sessions,
       specsManager: manager.kernelspecs,
       path,
       name: name || `Console ${count}`,

+ 1 - 1
packages/docregistry/src/context.ts

@@ -66,7 +66,7 @@ export class Context<T extends DocumentRegistry.IModel>
 
     let ext = PathExt.extname(this._path);
     this.sessionContext = new SessionContext({
-      manager: manager.sessions,
+      sessionManager: manager.sessions,
       specsManager: manager.kernelspecs,
       path: this._path,
       type: ext === '.ipynb' ? 'notebook' : 'file',

+ 1 - 1
packages/docregistry/src/registry.ts

@@ -584,7 +584,7 @@ export class DocumentRegistry implements IDisposable {
       language,
       shouldStart: widgetFactory.preferKernel,
       canStart: widgetFactory.canStartKernel,
-      shutdownOnClose: widgetFactory.shutdownOnClose
+      shutdownOnDispose: widgetFactory.shutdownOnClose
     };
   }
 

+ 1 - 1
packages/notebook/src/panel.ts

@@ -137,7 +137,7 @@ export class NotebookPanel extends DocumentWidget<Notebook, INotebookModel> {
     const kernelPreference = this.context.sessionContext.kernelPreference;
     this.context.sessionContext.kernelPreference = {
       ...kernelPreference,
-      shutdownOnClose: config.kernelShutdown
+      shutdownOnDispose: config.kernelShutdown
     };
   }
 

+ 3 - 3
testutils/src/index.ts

@@ -200,12 +200,12 @@ export function sleep<T>(milliseconds: number = 0, value?: T): Promise<T> {
 export async function createSessionContext(
   options: Partial<SessionContext.IOptions> = {}
 ): Promise<SessionContext> {
-  const manager = options.manager ?? Private.getManager().sessions;
+  const manager = options.sessionManager ?? Private.getManager().sessions;
   const specsManager = options.specsManager ?? Private.getManager().kernelspecs;
 
   await manager.ready;
   return new SessionContext({
-    manager,
+    sessionManager: manager,
     specsManager,
     path: options.path || UUID.uuid4(),
     name: options.name,
@@ -269,7 +269,7 @@ export async function initNotebookContext(
     kernelPreference: {
       shouldStart: startKernel,
       canStart: startKernel,
-      shutdownOnClose: true,
+      shutdownOnDispose: true,
       name: manager.kernelspecs.specs.default
     }
   });