浏览代码

Check debugging enable with kernel spec metadata.debugger

Jeremy Tuloup 5 年之前
父节点
当前提交
7465dc9553
共有 5 个文件被更改,包括 51 次插入19 次删除
  1. 2 1
      src/index.ts
  2. 27 6
      src/service.ts
  3. 13 8
      src/session.ts
  4. 4 1
      test/debugger.spec.ts
  5. 5 3
      test/service.spec.ts

+ 2 - 1
src/index.ts

@@ -271,7 +271,8 @@ const service: JupyterFrontEndPlugin<IDebugger> = {
   id: '@jupyterlab/debugger:service',
   autoStart: true,
   provides: IDebugger,
-  activate: () => new DebuggerService()
+  activate: (app: JupyterFrontEnd) =>
+    new DebuggerService({ specsManager: app.serviceManager.kernelspecs })
 };
 
 /**

+ 27 - 6
src/service.ts

@@ -1,7 +1,7 @@
 // Copyright (c) Jupyter Development Team.
 // Distributed under the terms of the Modified BSD License.
 
-import { Session } from '@jupyterlab/services';
+import { Session, KernelSpec } from '@jupyterlab/services';
 
 import { IDisposable } from '@lumino/disposable';
 
@@ -25,14 +25,17 @@ import { VariablesModel } from './variables/model';
 export class DebuggerService implements IDebugger, IDisposable {
   /**
    * Instantiate a new DebuggerService.
+   *
+   * @param options The instantiation options for a DebuggerService.
    */
-  constructor() {
+  constructor(options: DebuggerService.IOptions) {
     // Avoids setting session with invalid client
     // session should be set only when a notebook or
     // a console get the focus.
     // TODO: also checks that the notebook or console
     // runs a kernel with debugging ability
     this._session = null;
+    this._specsManager = options.specsManager;
     this._model = new DebuggerModel();
   }
 
@@ -129,14 +132,15 @@ export class DebuggerService implements IDebugger, IDisposable {
    * @param connection The session connection.
    */
   async isAvailable(connection: Session.ISessionConnection): Promise<boolean> {
+    await this._specsManager.ready;
     const kernel = connection?.kernel;
     if (!kernel) {
       return false;
     }
-    const info =
-      (((await kernel.info) as unknown) as IDebugger.ISession.IInfoReply) ??
-      null;
-    return !!(info?.debugger ?? false);
+    const name = kernel.name;
+    return !!(
+      this._specsManager.specs.kernelspecs[name].metadata?.['debugger'] ?? false
+    );
   }
 
   /**
@@ -623,11 +627,28 @@ export class DebuggerService implements IDebugger, IDisposable {
   private _modelChanged = new Signal<IDebugger, IDebugger.IModel>(this);
   private _eventMessage = new Signal<IDebugger, IDebugger.ISession.Event>(this);
 
+  private _specsManager: KernelSpec.IManager;
+
   private _hashMethod: (code: string) => string;
   private _tmpFilePrefix: string;
   private _tmpFileSuffix: string;
 }
 
+/**
+ * A namespace for `DebuggerService` statics.
+ */
+export namespace DebuggerService {
+  /**
+   * Instantiation options for a `DebuggerService`.
+   */
+  export interface IOptions {
+    /**
+     * The kernel specs manager.
+     */
+    specsManager: KernelSpec.IManager;
+  }
+}
+
 /**
  * A namespace for module private data.
  */

+ 13 - 8
src/session.ts

@@ -61,6 +61,17 @@ export class DebugSession implements IDebugger.ISession {
     }
 
     this._connection.iopubMessage.connect(this._handleEvent, this);
+
+    this._ready = new PromiseDelegate<void>();
+    const future = this.connection.kernel?.requestDebug({
+      type: 'request',
+      seq: 0,
+      command: 'debugInfo'
+    });
+    future.onReply = (msg: KernelMessage.IDebugReplyMsg): void => {
+      this._ready.resolve();
+      future.dispose();
+    };
   }
 
   /**
@@ -141,7 +152,7 @@ export class DebugSession implements IDebugger.ISession {
     command: K,
     args: IDebugger.ISession.Request[K]
   ): Promise<IDebugger.ISession.Response[K]> {
-    await this._ready();
+    await this._ready.promise;
     const message = await this._sendDebugMessage({
       type: 'request',
       seq: this._seq++,
@@ -192,14 +203,8 @@ export class DebugSession implements IDebugger.ISession {
     return reply.promise;
   }
 
-  /**
-   * A promise that resolves when the kernel is ready.
-   */
-  private _ready(): Promise<KernelMessage.IInfoReply> {
-    return this._connection?.kernel?.info;
-  }
-
   private _seq = 0;
+  private _ready = new PromiseDelegate<void>();
   private _connection: Session.ISessionConnection;
   private _isDisposed = false;
   private _isStarted = false;

+ 4 - 1
test/debugger.spec.ts

@@ -5,6 +5,8 @@ import {
 
 import { JupyterServer } from '@jupyterlab/testutils';
 
+import { KernelSpecManager } from '@jupyterlab/services';
+
 import { CommandRegistry } from '@lumino/commands';
 
 import { Debugger } from '../src/debugger';
@@ -28,7 +30,8 @@ afterAll(async () => {
 });
 
 describe('Debugger', () => {
-  const service = new DebuggerService();
+  const specsManager = new KernelSpecManager();
+  const service = new DebuggerService({ specsManager });
   const registry = new CommandRegistry();
   const factoryService = new CodeMirrorEditorFactory();
   const mimeTypeService = new CodeMirrorMimeTypeService();

+ 5 - 3
test/service.spec.ts

@@ -1,4 +1,4 @@
-import { Session } from '@jupyterlab/services';
+import { Session, KernelSpecManager } from '@jupyterlab/services';
 
 import {
   createSession,
@@ -28,7 +28,8 @@ afterAll(async () => {
 });
 
 describe('Debugging support', () => {
-  const service = new DebuggerService();
+  const specsManager = new KernelSpecManager();
+  const service = new DebuggerService({ specsManager });
   let xpython: Session.ISessionConnection;
   let ipykernel: Session.ISessionConnection;
 
@@ -65,6 +66,7 @@ describe('Debugging support', () => {
 });
 
 describe('DebuggerService', () => {
+  const specsManager = new KernelSpecManager();
   let connection: Session.ISessionConnection;
   let model: DebuggerModel;
   let session: IDebugger.ISession;
@@ -79,7 +81,7 @@ describe('DebuggerService', () => {
     await connection.changeKernel({ name: 'xpython' });
     session = new DebugSession({ connection });
     model = new DebuggerModel();
-    service = new DebuggerService();
+    service = new DebuggerService({ specsManager });
   });
 
   afterEach(async () => {