From c6c1e8b24d57b4f729e9f6a988ed1ef97d001aa7 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 30 Oct 2024 16:10:16 +1100 Subject: [PATCH 1/8] Jupyter API to get Env associated with Notebooks --- pythonExtensionApi/src/main.ts | 4 +- src/client/api.ts | 6 +- src/client/api/types.ts | 4 +- src/client/environmentApi.ts | 18 +++++ src/client/jupyter/jupyterIntegration.ts | 83 +++++++++++++++++++++++- src/test/environmentApi.unit.test.ts | 16 ++++- 6 files changed, 121 insertions(+), 10 deletions(-) diff --git a/pythonExtensionApi/src/main.ts b/pythonExtensionApi/src/main.ts index 154ffbbd857a..2173245cbb28 100644 --- a/pythonExtensionApi/src/main.ts +++ b/pythonExtensionApi/src/main.ts @@ -227,9 +227,9 @@ export type EnvironmentsChangeEvent = { export type ActiveEnvironmentPathChangeEvent = EnvironmentPath & { /** - * Workspace folder the environment changed for. + * Resource the environment changed for. */ - readonly resource: WorkspaceFolder | undefined; + readonly resource: Resource | undefined; }; /** diff --git a/src/client/api.ts b/src/client/api.ts index 899326647808..bf04a331a8b6 100644 --- a/src/client/api.ts +++ b/src/client/api.ts @@ -15,7 +15,7 @@ import { IConfigurationService, Resource } from './common/types'; import { getDebugpyLauncherArgs } from './debugger/extension/adapter/remoteLaunchers'; import { IInterpreterService } from './interpreter/contracts'; import { IServiceContainer, IServiceManager } from './ioc/types'; -import { JupyterExtensionIntegration } from './jupyter/jupyterIntegration'; +import { JupyterExtensionIntegration, JupyterExtensionPythonEnvironments, type JupyterPythonEnvironmentApi } from './jupyter/jupyterIntegration'; import { traceError } from './logging'; import { IDiscoveryAPI } from './pythonEnvironments/base/locator'; import { buildEnvironmentApi } from './environmentApi'; @@ -33,11 +33,13 @@ export function buildApi( const configurationService = serviceContainer.get(IConfigurationService); const interpreterService = serviceContainer.get(IInterpreterService); serviceManager.addSingleton(JupyterExtensionIntegration, JupyterExtensionIntegration); + serviceManager.addSingleton(JupyterExtensionPythonEnvironments, JupyterExtensionPythonEnvironments); serviceManager.addSingleton( TensorboardExtensionIntegration, TensorboardExtensionIntegration, ); const jupyterIntegration = serviceContainer.get(JupyterExtensionIntegration); + const jupyterPythonEnvApi = serviceContainer.get(JupyterExtensionPythonEnvironments); const tensorboardIntegration = serviceContainer.get( TensorboardExtensionIntegration, ); @@ -146,7 +148,7 @@ export function buildApi( stop: (client: BaseLanguageClient): Promise => client.stop(), getTelemetryReporter: () => getTelemetryReporter(), }, - environments: buildEnvironmentApi(discoveryApi, serviceContainer), + environments: buildEnvironmentApi(discoveryApi, serviceContainer, jupyterPythonEnvApi), }; // In test environment return the DI Container. diff --git a/src/client/api/types.ts b/src/client/api/types.ts index 4e67334121fb..95556aacbd90 100644 --- a/src/client/api/types.ts +++ b/src/client/api/types.ts @@ -227,9 +227,9 @@ export type EnvironmentsChangeEvent = { export type ActiveEnvironmentPathChangeEvent = EnvironmentPath & { /** - * Workspace folder the environment changed for. + * Resource the environment changed for. */ - readonly resource: WorkspaceFolder | undefined; + readonly resource: Resource | undefined; }; /** diff --git a/src/client/environmentApi.ts b/src/client/environmentApi.ts index 6c4b5cf94d92..b729405e2b12 100644 --- a/src/client/environmentApi.ts +++ b/src/client/environmentApi.ts @@ -33,6 +33,7 @@ import { } from './api/types'; import { buildEnvironmentCreationApi } from './pythonEnvironments/creation/createEnvApi'; import { EnvironmentKnownCache } from './environmentKnownCache'; +import type { JupyterPythonEnvironmentApi } from './jupyter/jupyterIntegration'; type ActiveEnvironmentChangeEvent = { resource: WorkspaceFolder | undefined; @@ -115,6 +116,7 @@ function filterUsingVSCodeContext(e: PythonEnvInfo) { export function buildEnvironmentApi( discoveryApi: IDiscoveryAPI, serviceContainer: IServiceContainer, + jupyterPythonEnvsApi: JupyterPythonEnvironmentApi, ): PythonExtension['environments'] { const interpreterPathService = serviceContainer.get(IInterpreterPathService); const configService = serviceContainer.get(IConfigurationService); @@ -206,6 +208,14 @@ export function buildEnvironmentApi( }), onEnvironmentsChanged, onEnvironmentVariablesChanged, + jupyterPythonEnvsApi.onDidChangePythonEnvironment((e) => { + const jupyterEnv = environmentApi.getActiveEnvironmentPath(e); + onDidActiveInterpreterChangedEvent.fire({ + id: jupyterEnv.id, + path: jupyterEnv.path, + resource: e, + }); + }, undefined), ); if (!knownCache!) { knownCache = initKnownCache(); @@ -224,6 +234,14 @@ export function buildEnvironmentApi( getActiveEnvironmentPath(resource?: Resource) { sendApiTelemetry('getActiveEnvironmentPath'); resource = resource && 'uri' in resource ? resource.uri : resource; + const jupyterEnv = resource ? jupyterPythonEnvsApi.getPythonEnvironment(resource) : undefined; + if (jupyterEnv) { + traceVerbose('Python Environment returned from Jupyter', resource?.fsPath, jupyterEnv.id); + return { + id: jupyterEnv.id, + path: jupyterEnv.path, + }; + } const path = configService.getSettings(resource).pythonPath; const id = path === 'python' ? 'DEFAULT_PYTHON' : getEnvID(path); return { diff --git a/src/client/jupyter/jupyterIntegration.ts b/src/client/jupyter/jupyterIntegration.ts index 69583b744da9..d920fa808053 100644 --- a/src/client/jupyter/jupyterIntegration.ts +++ b/src/client/jupyter/jupyterIntegration.ts @@ -6,7 +6,7 @@ import { inject, injectable, named } from 'inversify'; import { dirname } from 'path'; -import { Extension, Memento, Uri } from 'vscode'; +import { EventEmitter, Extension, Memento, Uri, workspace, type Event } from 'vscode'; import type { SemVer } from 'semver'; import { IContextKeyManager, IWorkspaceService } from '../common/application/types'; import { JUPYTER_EXTENSION_ID, PYLANCE_EXTENSION_ID } from '../common/constants'; @@ -23,6 +23,7 @@ import { PylanceApi } from '../activation/node/pylanceApi'; import { ExtensionContextKey } from '../common/application/contextKeys'; import { getDebugpyPath } from '../debugger/pythonDebugger'; import type { Environment } from '../api/types'; +import { DisposableBase } from '../common/utils/resourceLifecycle'; type PythonApiForJupyterExtension = { /** @@ -170,3 +171,83 @@ export class JupyterExtensionIntegration { } } } + + +export interface JupyterPythonEnvironmentApi { + /** + * This event is triggered when the environment associated with a Jupyter Notebook or Interactive Window changes. + * The Uri in the event is the Uri of the Notebook/IW. + */ + onDidChangePythonEnvironment: Event; + /** + * Returns the EnvironmentPath to the Python environment associated with a Jupyter Notebook or Interactive Window. + * If the Uri is not associated with a Jupyter Notebook or Interactive Window, then this method returns undefined. + * @param uri + */ + getPythonEnvironment( + uri: Uri, + ): + | undefined + | { + /** + * The ID of the environment. + */ + readonly id: string; + /** + * Path to environment folder or path to python executable that uniquely identifies an environment. Environments + * lacking a python executable are identified by environment folder paths, whereas other envs can be identified + * using python executable path. + */ + readonly path: string; + }; +} + +// eslint-disable-next-line max-classes-per-file + +@injectable() +export class JupyterExtensionPythonEnvironments extends DisposableBase implements JupyterPythonEnvironmentApi { + private jupyterExtension?: JupyterPythonEnvironmentApi; + + private readonly _onDidChangePythonEnvironment = this._register(new EventEmitter()); + + public readonly onDidChangePythonEnvironment = this._onDidChangePythonEnvironment.event; + + constructor( + @inject(IExtensions) private readonly extensions: IExtensions, + ) { + super(); + } + + public getPythonEnvironment(uri: Uri): undefined | + { + /** + * The ID of the environment. + */ + readonly id: string; + /** + * Path to environment folder or path to python executable that uniquely identifies an environment. Environments + * lacking a python executable are identified by environment folder paths, whereas other envs can be identified + * using python executable path. + */ + readonly path: string; + } { + return isJupyterResource(uri) ? this.getJupyterApi()?.getPythonEnvironment(uri) : undefined; + } + + private getJupyterApi(){ + if (!this.jupyterExtension) { + const api = this.extensions.getExtension(JUPYTER_EXTENSION_ID)?.exports; + if (!api) { + return undefined; + } + this.jupyterExtension = api; + this._register(api.onDidChangePythonEnvironment(this._onDidChangePythonEnvironment.fire, this._onDidChangePythonEnvironment)); + } + return this.jupyterExtension; + } +} + +function isJupyterResource(resource: Uri): boolean { + // Jupyter extension only deals with Notebooks and Interactive Windows. + return resource.fsPath.endsWith('.ipynb') || workspace.notebookDocuments.some((item) => item.uri.toString() === resource.toString()); +} diff --git a/src/test/environmentApi.unit.test.ts b/src/test/environmentApi.unit.test.ts index 012e1a0bfc69..2e5d13161f7b 100644 --- a/src/test/environmentApi.unit.test.ts +++ b/src/test/environmentApi.unit.test.ts @@ -38,6 +38,7 @@ import { EnvironmentsChangeEvent, PythonExtension, } from '../client/api/types'; +import { JupyterPythonEnvironmentApi } from '../client/jupyter/jupyterIntegration'; suite('Python Environment API', () => { const workspacePath = 'path/to/workspace'; @@ -80,7 +81,6 @@ suite('Python Environment API', () => { onDidChangeRefreshState = new EventEmitter(); onDidChangeEnvironments = new EventEmitter(); onDidChangeEnvironmentVariables = new EventEmitter(); - serviceContainer.setup((s) => s.get(IExtensions)).returns(() => extensions.object); serviceContainer.setup((s) => s.get(IInterpreterPathService)).returns(() => interpreterPathService.object); serviceContainer.setup((s) => s.get(IConfigurationService)).returns(() => configService.object); @@ -94,8 +94,13 @@ suite('Python Environment API', () => { discoverAPI.setup((d) => d.onProgress).returns(() => onDidChangeRefreshState.event); discoverAPI.setup((d) => d.onChanged).returns(() => onDidChangeEnvironments.event); discoverAPI.setup((d) => d.getEnvs()).returns(() => []); + const onDidChangePythonEnvironment = new EventEmitter(); + const jupyterApi: JupyterPythonEnvironmentApi = { + onDidChangePythonEnvironment: onDidChangePythonEnvironment.event, + getPythonEnvironment: (_uri: Uri) => undefined, + }; - environmentApi = buildEnvironmentApi(discoverAPI.object, serviceContainer.object); + environmentApi = buildEnvironmentApi(discoverAPI.object, serviceContainer.object, jupyterApi); }); teardown(() => { @@ -323,7 +328,12 @@ suite('Python Environment API', () => { }, ]; discoverAPI.setup((d) => d.getEnvs()).returns(() => envs); - environmentApi = buildEnvironmentApi(discoverAPI.object, serviceContainer.object); + const onDidChangePythonEnvironment = new EventEmitter(); + const jupyterApi: JupyterPythonEnvironmentApi = { + onDidChangePythonEnvironment: onDidChangePythonEnvironment.event, + getPythonEnvironment: (_uri: Uri) => undefined, + }; + environmentApi = buildEnvironmentApi(discoverAPI.object, serviceContainer.object, jupyterApi); const actual = environmentApi.known; const actualEnvs = actual?.map((a) => (a as EnvironmentReference).internal); assert.deepEqual( From 9f84629d6552d0a40d6cd1e8b90a03b1f84affbf Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 30 Oct 2024 16:31:55 +1100 Subject: [PATCH 2/8] Fixes --- src/client/environmentApi.ts | 37 ++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/client/environmentApi.ts b/src/client/environmentApi.ts index b729405e2b12..2d6918da76ba 100644 --- a/src/client/environmentApi.ts +++ b/src/client/environmentApi.ts @@ -148,6 +148,25 @@ export function buildEnvironmentApi( }) .ignoreErrors(); } + + function getActiveEnvironmentPath(resource?: Resource) { + resource = resource && 'uri' in resource ? resource.uri : resource; + const jupyterEnv = resource ? jupyterPythonEnvsApi.getPythonEnvironment(resource) : undefined; + if (jupyterEnv) { + traceVerbose('Python Environment returned from Jupyter', resource?.fsPath, jupyterEnv.id); + return { + id: jupyterEnv.id, + path: jupyterEnv.path, + }; + } + const path = configService.getSettings(resource).pythonPath; + const id = path === 'python' ? 'DEFAULT_PYTHON' : getEnvID(path); + return { + id, + path, + }; + } + disposables.push( discoveryApi.onProgress((e) => { if (e.stage === ProgressReportStage.discoveryFinished) { @@ -209,7 +228,7 @@ export function buildEnvironmentApi( onEnvironmentsChanged, onEnvironmentVariablesChanged, jupyterPythonEnvsApi.onDidChangePythonEnvironment((e) => { - const jupyterEnv = environmentApi.getActiveEnvironmentPath(e); + const jupyterEnv = getActiveEnvironmentPath(e); onDidActiveInterpreterChangedEvent.fire({ id: jupyterEnv.id, path: jupyterEnv.path, @@ -233,21 +252,7 @@ export function buildEnvironmentApi( }, getActiveEnvironmentPath(resource?: Resource) { sendApiTelemetry('getActiveEnvironmentPath'); - resource = resource && 'uri' in resource ? resource.uri : resource; - const jupyterEnv = resource ? jupyterPythonEnvsApi.getPythonEnvironment(resource) : undefined; - if (jupyterEnv) { - traceVerbose('Python Environment returned from Jupyter', resource?.fsPath, jupyterEnv.id); - return { - id: jupyterEnv.id, - path: jupyterEnv.path, - }; - } - const path = configService.getSettings(resource).pythonPath; - const id = path === 'python' ? 'DEFAULT_PYTHON' : getEnvID(path); - return { - id, - path, - }; + return getActiveEnvironmentPath(resource); }, updateActiveEnvironmentPath(env: Environment | EnvironmentPath | string, resource?: Resource): Promise { sendApiTelemetry('updateActiveEnvironmentPath'); From dd5de828aebcd07230f0223f98fb7e309eb78621 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 30 Oct 2024 16:35:43 +1100 Subject: [PATCH 3/8] Fix tests --- src/test/api.functional.test.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/test/api.functional.test.ts b/src/test/api.functional.test.ts index eea0fb920b15..af9c0af1e4e4 100644 --- a/src/test/api.functional.test.ts +++ b/src/test/api.functional.test.ts @@ -19,6 +19,8 @@ import { ServiceManager } from '../client/ioc/serviceManager'; import { IServiceContainer, IServiceManager } from '../client/ioc/types'; import { IDiscoveryAPI } from '../client/pythonEnvironments/base/locator'; import * as pythonDebugger from '../client/debugger/pythonDebugger'; +import { JupyterExtensionPythonEnvironments, JupyterPythonEnvironmentApi } from '../client/jupyter/jupyterIntegration'; +import { EventEmitter, type Uri } from 'vscode'; suite('Extension API', () => { const debuggerPath = path.join(EXTENSION_ROOT_DIR, 'python_files', 'lib', 'python', 'debugpy'); @@ -49,6 +51,12 @@ suite('Extension API', () => { instance(environmentVariablesProvider), ); when(serviceContainer.get(IInterpreterService)).thenReturn(instance(interpreterService)); + const onDidChangePythonEnvironment = new EventEmitter(); + const jupyterApi: JupyterPythonEnvironmentApi = { + onDidChangePythonEnvironment: onDidChangePythonEnvironment.event, + getPythonEnvironment: (_uri: Uri) => undefined, + }; + when(serviceContainer.get(JupyterExtensionPythonEnvironments)).thenReturn(jupyterApi); when(serviceContainer.get(IDisposableRegistry)).thenReturn([]); getDebugpyPathStub = sinon.stub(pythonDebugger, 'getDebugpyPath'); getDebugpyPathStub.resolves(debuggerPath); From bbdf9d54bfa31f52f2e0541093a404325c2201b7 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 30 Oct 2024 16:48:06 +1100 Subject: [PATCH 4/8] fix linter --- src/client/jupyter/jupyterIntegration.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/client/jupyter/jupyterIntegration.ts b/src/client/jupyter/jupyterIntegration.ts index d920fa808053..9fdc270c7f1a 100644 --- a/src/client/jupyter/jupyterIntegration.ts +++ b/src/client/jupyter/jupyterIntegration.ts @@ -1,6 +1,6 @@ /* eslint-disable comma-dangle */ -/* eslint-disable implicit-arrow-linebreak */ +/* eslint-disable implicit-arrow-linebreak, max-classes-per-file */ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. @@ -202,7 +202,6 @@ export interface JupyterPythonEnvironmentApi { }; } -// eslint-disable-next-line max-classes-per-file @injectable() export class JupyterExtensionPythonEnvironments extends DisposableBase implements JupyterPythonEnvironmentApi { From a9f7c2726377f7c0e9f665852da3e5ff67f39ad1 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Thu, 31 Oct 2024 11:33:57 +1100 Subject: [PATCH 5/8] Fix compilation errors --- src/client/api.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/client/api.ts b/src/client/api.ts index bf04a331a8b6..15fb4d688a89 100644 --- a/src/client/api.ts +++ b/src/client/api.ts @@ -15,7 +15,11 @@ import { IConfigurationService, Resource } from './common/types'; import { getDebugpyLauncherArgs } from './debugger/extension/adapter/remoteLaunchers'; import { IInterpreterService } from './interpreter/contracts'; import { IServiceContainer, IServiceManager } from './ioc/types'; -import { JupyterExtensionIntegration, JupyterExtensionPythonEnvironments, type JupyterPythonEnvironmentApi } from './jupyter/jupyterIntegration'; +import { + JupyterExtensionIntegration, + JupyterExtensionPythonEnvironments, + JupyterPythonEnvironmentApi, +} from './jupyter/jupyterIntegration'; import { traceError } from './logging'; import { IDiscoveryAPI } from './pythonEnvironments/base/locator'; import { buildEnvironmentApi } from './environmentApi'; @@ -33,7 +37,10 @@ export function buildApi( const configurationService = serviceContainer.get(IConfigurationService); const interpreterService = serviceContainer.get(IInterpreterService); serviceManager.addSingleton(JupyterExtensionIntegration, JupyterExtensionIntegration); - serviceManager.addSingleton(JupyterExtensionPythonEnvironments, JupyterExtensionPythonEnvironments); + serviceManager.addSingleton( + JupyterExtensionPythonEnvironments, + JupyterExtensionPythonEnvironments, + ); serviceManager.addSingleton( TensorboardExtensionIntegration, TensorboardExtensionIntegration, From e66a377326ae6405d083b215802c22818434b9a3 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Thu, 31 Oct 2024 11:39:46 +1100 Subject: [PATCH 6/8] Fix compilation --- src/client/jupyter/jupyterIntegration.ts | 75 +++++++++++++----------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/src/client/jupyter/jupyterIntegration.ts b/src/client/jupyter/jupyterIntegration.ts index 9fdc270c7f1a..5f19542ab5c7 100644 --- a/src/client/jupyter/jupyterIntegration.ts +++ b/src/client/jupyter/jupyterIntegration.ts @@ -6,7 +6,7 @@ import { inject, injectable, named } from 'inversify'; import { dirname } from 'path'; -import { EventEmitter, Extension, Memento, Uri, workspace, type Event } from 'vscode'; +import { EventEmitter, Extension, Memento, Uri, workspace, Event } from 'vscode'; import type { SemVer } from 'semver'; import { IContextKeyManager, IWorkspaceService } from '../common/application/types'; import { JUPYTER_EXTENSION_ID, PYLANCE_EXTENSION_ID } from '../common/constants'; @@ -172,7 +172,6 @@ export class JupyterExtensionIntegration { } } - export interface JupyterPythonEnvironmentApi { /** * This event is triggered when the environment associated with a Jupyter Notebook or Interactive Window changes. @@ -189,58 +188,63 @@ export interface JupyterPythonEnvironmentApi { ): | undefined | { - /** - * The ID of the environment. - */ - readonly id: string; - /** - * Path to environment folder or path to python executable that uniquely identifies an environment. Environments - * lacking a python executable are identified by environment folder paths, whereas other envs can be identified - * using python executable path. - */ - readonly path: string; - }; + /** + * The ID of the environment. + */ + readonly id: string; + /** + * Path to environment folder or path to python executable that uniquely identifies an environment. Environments + * lacking a python executable are identified by environment folder paths, whereas other envs can be identified + * using python executable path. + */ + readonly path: string; + }; } - @injectable() -export class JupyterExtensionPythonEnvironments extends DisposableBase implements JupyterPythonEnvironmentApi { +export class JupyterExtensionPythonEnvironments extends DisposableBase implements JupyterPythonEnvironmentApi { private jupyterExtension?: JupyterPythonEnvironmentApi; private readonly _onDidChangePythonEnvironment = this._register(new EventEmitter()); public readonly onDidChangePythonEnvironment = this._onDidChangePythonEnvironment.event; - constructor( - @inject(IExtensions) private readonly extensions: IExtensions, - ) { + constructor(@inject(IExtensions) private readonly extensions: IExtensions) { super(); } - public getPythonEnvironment(uri: Uri): undefined | - { - /** - * The ID of the environment. - */ - readonly id: string; - /** - * Path to environment folder or path to python executable that uniquely identifies an environment. Environments - * lacking a python executable are identified by environment folder paths, whereas other envs can be identified - * using python executable path. - */ - readonly path: string; - } { + public getPythonEnvironment( + uri: Uri, + ): + | undefined + | { + /** + * The ID of the environment. + */ + readonly id: string; + /** + * Path to environment folder or path to python executable that uniquely identifies an environment. Environments + * lacking a python executable are identified by environment folder paths, whereas other envs can be identified + * using python executable path. + */ + readonly path: string; + } { return isJupyterResource(uri) ? this.getJupyterApi()?.getPythonEnvironment(uri) : undefined; } - private getJupyterApi(){ + private getJupyterApi() { if (!this.jupyterExtension) { const api = this.extensions.getExtension(JUPYTER_EXTENSION_ID)?.exports; if (!api) { return undefined; } this.jupyterExtension = api; - this._register(api.onDidChangePythonEnvironment(this._onDidChangePythonEnvironment.fire, this._onDidChangePythonEnvironment)); + this._register( + api.onDidChangePythonEnvironment( + this._onDidChangePythonEnvironment.fire, + this._onDidChangePythonEnvironment, + ), + ); } return this.jupyterExtension; } @@ -248,5 +252,8 @@ export class JupyterExtensionPythonEnvironments extends DisposableBase implement function isJupyterResource(resource: Uri): boolean { // Jupyter extension only deals with Notebooks and Interactive Windows. - return resource.fsPath.endsWith('.ipynb') || workspace.notebookDocuments.some((item) => item.uri.toString() === resource.toString()); + return ( + resource.fsPath.endsWith('.ipynb') || + workspace.notebookDocuments.some((item) => item.uri.toString() === resource.toString()) + ); } From 6730ad3bac699b4b3d62d3b9a6785d2f988eeb8e Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Thu, 31 Oct 2024 11:40:25 +1100 Subject: [PATCH 7/8] fixes --- src/test/api.functional.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/api.functional.test.ts b/src/test/api.functional.test.ts index af9c0af1e4e4..1b6bf54bb1ef 100644 --- a/src/test/api.functional.test.ts +++ b/src/test/api.functional.test.ts @@ -20,7 +20,7 @@ import { IServiceContainer, IServiceManager } from '../client/ioc/types'; import { IDiscoveryAPI } from '../client/pythonEnvironments/base/locator'; import * as pythonDebugger from '../client/debugger/pythonDebugger'; import { JupyterExtensionPythonEnvironments, JupyterPythonEnvironmentApi } from '../client/jupyter/jupyterIntegration'; -import { EventEmitter, type Uri } from 'vscode'; +import { EventEmitter, Uri } from 'vscode'; suite('Extension API', () => { const debuggerPath = path.join(EXTENSION_ROOT_DIR, 'python_files', 'lib', 'python', 'debugpy'); From e9d92b50e980e8e25568be24161e481c768c834e Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Thu, 31 Oct 2024 11:40:29 +1100 Subject: [PATCH 8/8] fixes --- src/test/api.functional.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/api.functional.test.ts b/src/test/api.functional.test.ts index 1b6bf54bb1ef..1149dcb7da9d 100644 --- a/src/test/api.functional.test.ts +++ b/src/test/api.functional.test.ts @@ -56,7 +56,9 @@ suite('Extension API', () => { onDidChangePythonEnvironment: onDidChangePythonEnvironment.event, getPythonEnvironment: (_uri: Uri) => undefined, }; - when(serviceContainer.get(JupyterExtensionPythonEnvironments)).thenReturn(jupyterApi); + when(serviceContainer.get(JupyterExtensionPythonEnvironments)).thenReturn( + jupyterApi, + ); when(serviceContainer.get(IDisposableRegistry)).thenReturn([]); getDebugpyPathStub = sinon.stub(pythonDebugger, 'getDebugpyPath'); getDebugpyPathStub.resolves(debuggerPath);