33
44import { inject , injectable , named } from 'inversify' ;
55import { CancellationToken , Uri , workspace } from 'vscode' ;
6- import { PythonEnvironment } from '../../platform/pythonEnvironments/info' ;
7- import { IDeepnoteToolkitInstaller , DEEPNOTE_TOOLKIT_WHEEL_URL , DEEPNOTE_TOOLKIT_VERSION } from './types' ;
8- import { IProcessServiceFactory } from '../../platform/common/process/types.node' ;
9- import { logger } from '../../platform/logging' ;
10- import { IOutputChannel , IExtensionContext } from '../../platform/common/types' ;
6+ import { Cancellation } from '../../platform/common/cancellation' ;
117import { STANDARD_OUTPUT_CHANNEL } from '../../platform/common/constants' ;
128import { IFileSystem } from '../../platform/common/platform/types' ;
13- import { Cancellation } from '../../platform/common/cancellation' ;
14- import { DeepnoteVenvCreationError , DeepnoteToolkitInstallError } from '../../platform/errors/deepnoteKernelErrors' ;
9+ import { IProcessServiceFactory } from '../../platform/common/process/types.node' ;
10+ import { IExtensionContext , IOutputChannel } from '../../platform/common/types' ;
11+ import { DeepnoteToolkitInstallError , DeepnoteVenvCreationError } from '../../platform/errors/deepnoteKernelErrors' ;
12+ import { logger } from '../../platform/logging' ;
13+ import { PythonEnvironment } from '../../platform/pythonEnvironments/info' ;
14+ import {
15+ DEEPNOTE_TOOLKIT_VERSION ,
16+ DEEPNOTE_TOOLKIT_WHEEL_URL ,
17+ IDeepnoteToolkitInstaller ,
18+ VenvAndToolkitInstallation
19+ } from './types' ;
1520
1621/**
1722 * Handles installation of the deepnote-toolkit Python package.
@@ -20,7 +25,7 @@ import { DeepnoteVenvCreationError, DeepnoteToolkitInstallError } from '../../pl
2025export class DeepnoteToolkitInstaller implements IDeepnoteToolkitInstaller {
2126 private readonly venvPythonPaths : Map < string , Uri > = new Map ( ) ;
2227 // Track in-flight installations per venv path to prevent concurrent installs
23- private readonly pendingInstallations : Map < string , Promise < PythonEnvironment > > = new Map ( ) ;
28+ private readonly pendingInstallations : Map < string , Promise < VenvAndToolkitInstallation > > = new Map ( ) ;
2429
2530 constructor (
2631 @inject ( IProcessServiceFactory ) private readonly processServiceFactory : IProcessServiceFactory ,
@@ -77,7 +82,7 @@ export class DeepnoteToolkitInstaller implements IDeepnoteToolkitInstaller {
7782 baseInterpreter : PythonEnvironment ,
7883 venvPath : Uri ,
7984 token ?: CancellationToken
80- ) : Promise < PythonEnvironment > {
85+ ) : Promise < VenvAndToolkitInstallation > {
8186 const venvKey = venvPath . fsPath ;
8287
8388 logger . info ( `Ensuring virtual environment at ${ venvKey } ` ) ;
@@ -96,19 +101,22 @@ export class DeepnoteToolkitInstaller implements IDeepnoteToolkitInstaller {
96101
97102 // Check if venv already exists with toolkit installed
98103 const existingVenv = await this . getVenvInterpreterByPath ( venvPath ) ;
99- if ( existingVenv && ( await this . isToolkitInstalled ( existingVenv ) ) ) {
100- logger . info ( `deepnote-toolkit venv already exists at ${ venvPath . fsPath } ` ) ;
104+ if ( existingVenv ) {
105+ const toolkitVersion = await this . isToolkitInstalled ( existingVenv ) ;
106+ if ( toolkitVersion != null ) {
107+ logger . info ( `deepnote-toolkit venv already exists at ${ venvPath . fsPath } ` ) ;
101108
102- // Ensure kernel spec is installed (may have been deleted or never installed)
103- try {
104- await this . installKernelSpec ( existingVenv , venvPath ) ;
105- } catch ( ex ) {
106- logger . warn ( `Failed to ensure kernel spec installed: ${ ex } ` ) ;
107- // Don't fail - continue with existing venv
108- }
109+ // Ensure kernel spec is installed (may have been deleted or never installed)
110+ try {
111+ await this . installKernelSpec ( existingVenv , venvPath ) ;
112+ } catch ( ex ) {
113+ logger . warn ( `Failed to ensure kernel spec installed: ${ ex } ` ) ;
114+ // Don't fail - continue with existing venv
115+ }
109116
110- logger . info ( `Venv ready at ${ venvPath . fsPath } ` ) ;
111- return existingVenv ;
117+ logger . info ( `Venv ready at ${ venvPath . fsPath } ` ) ;
118+ return { pythonInterpreter : existingVenv , toolkitVersion } ;
119+ }
112120 }
113121
114122 // Double-check for race condition
@@ -193,7 +201,7 @@ export class DeepnoteToolkitInstaller implements IDeepnoteToolkitInstaller {
193201 baseInterpreter : PythonEnvironment ,
194202 venvPath : Uri ,
195203 token ?: CancellationToken
196- ) : Promise < PythonEnvironment > {
204+ ) : Promise < VenvAndToolkitInstallation > {
197205 try {
198206 Cancellation . throwIfCanceled ( token ) ;
199207
@@ -288,7 +296,8 @@ export class DeepnoteToolkitInstaller implements IDeepnoteToolkitInstaller {
288296 }
289297
290298 // Verify installation
291- if ( await this . isToolkitInstalled ( venvInterpreter ) ) {
299+ const installedToolkitVersion = await this . isToolkitInstalled ( venvInterpreter ) ;
300+ if ( installedToolkitVersion != null ) {
292301 logger . info ( 'deepnote-toolkit installed successfully in venv' ) ;
293302
294303 // Install kernel spec so the kernel uses this venv's Python
@@ -300,7 +309,7 @@ export class DeepnoteToolkitInstaller implements IDeepnoteToolkitInstaller {
300309 }
301310
302311 this . outputChannel . appendLine ( '✓ Deepnote toolkit ready' ) ;
303- return venvInterpreter ;
312+ return { pythonInterpreter : venvInterpreter , toolkitVersion : installedToolkitVersion } ;
304313 } else {
305314 logger . error ( 'deepnote-toolkit installation failed' ) ;
306315 this . outputChannel . appendLine ( '✗ deepnote-toolkit installation failed' ) ;
@@ -334,18 +343,19 @@ export class DeepnoteToolkitInstaller implements IDeepnoteToolkitInstaller {
334343 }
335344 }
336345
337- private async isToolkitInstalled ( interpreter : PythonEnvironment ) : Promise < boolean > {
346+ private async isToolkitInstalled ( interpreter : PythonEnvironment ) : Promise < string | undefined > {
338347 try {
339348 // Use undefined as resource to get full system environment
340349 const processService = await this . processServiceFactory . create ( undefined ) ;
341350 const result = await processService . exec ( interpreter . uri . fsPath , [
342351 '-c' ,
343- " import deepnote_toolkit; print('installed')"
352+ ' import deepnote_toolkit; print(deepnote_toolkit.__version__)'
344353 ] ) ;
345- return result . stdout . toLowerCase ( ) . includes ( 'installed' ) ;
354+ logger . info ( `isToolkitInstalled result: ${ result . stdout } ` ) ;
355+ return result . stdout . trim ( ) ;
346356 } catch ( ex ) {
347357 logger . debug ( `deepnote-toolkit not found: ${ ex } ` ) ;
348- return false ;
358+ return undefined ;
349359 }
350360 }
351361
0 commit comments