@@ -9,6 +9,8 @@ import { spawnProcess } from '../../common/childProcess.apis';
99import { ENVS_EXTENSION_ID , PYTHON_EXTENSION_ID } from '../../common/constants' ;
1010import { getExtension } from '../../common/extension.apis' ;
1111import { traceError , traceVerbose , traceWarn } from '../../common/logging' ;
12+ import { EventNames } from '../../common/telemetry/constants' ;
13+ import { sendTelemetryEvent } from '../../common/telemetry/sender' ;
1214import { untildify , untildifyArray } from '../../common/utils/pathUtils' ;
1315import { isWindows } from '../../common/utils/platformUtils' ;
1416import { createRunningWorkerPool , WorkerPool } from '../../common/utils/workerPool' ;
@@ -78,17 +80,27 @@ export async function getNativePythonToolsPath(): Promise<string> {
7880 const envsExt = getExtension ( ENVS_EXTENSION_ID ) ;
7981 if ( envsExt ) {
8082 const petPath = path . join ( envsExt . extensionPath , 'python-env-tools' , 'bin' , isWindows ( ) ? 'pet.exe' : 'pet' ) ;
81- if ( await fs . pathExists ( petPath ) ) {
83+ const exists = await fs . pathExists ( petPath ) ;
84+ traceVerbose ( `[pet] Primary path (envs-ext): ${ petPath } — exists: ${ exists } ` ) ;
85+ if ( exists ) {
8286 return petPath ;
8387 }
88+ } else {
89+ traceVerbose ( `[pet] Envs extension (${ ENVS_EXTENSION_ID } ) not found; trying Python extension fallback` ) ;
8490 }
8591
8692 const python = getExtension ( PYTHON_EXTENSION_ID ) ;
8793 if ( ! python ) {
88- throw new Error ( 'Python extension not found' ) ;
94+ throw new Error ( 'Python extension not found and envs extension pet binary is missing ' ) ;
8995 }
9096
91- return path . join ( python . extensionPath , 'python-env-tools' , 'bin' , isWindows ( ) ? 'pet.exe' : 'pet' ) ;
97+ const fallbackPath = path . join ( python . extensionPath , 'python-env-tools' , 'bin' , isWindows ( ) ? 'pet.exe' : 'pet' ) ;
98+ const fallbackExists = await fs . pathExists ( fallbackPath ) ;
99+ traceVerbose ( `[pet] Fallback path (python-ext): ${ fallbackPath } — exists: ${ fallbackExists } ` ) ;
100+ if ( ! fallbackExists ) {
101+ throw new Error ( `Python finder binary not found at: ${ fallbackPath } ` ) ;
102+ }
103+ return fallbackPath ;
92104}
93105
94106export interface NativeEnvInfo {
@@ -224,6 +236,7 @@ class NativePythonFinderImpl implements NativePythonFinder {
224236 private startFailed : boolean = false ;
225237 private restartAttempts : number = 0 ;
226238 private isRestarting : boolean = false ;
239+ private isDisposed : boolean = false ;
227240 private readonly configureRetry = new ConfigureRetryState ( ) ;
228241
229242 constructor (
@@ -426,6 +439,7 @@ class NativePythonFinderImpl implements NativePythonFinder {
426439 }
427440
428441 public dispose ( ) {
442+ this . isDisposed = true ;
429443 this . pool . stop ( ) ;
430444 this . startDisposables . forEach ( ( d ) => d . dispose ( ) ) ;
431445 this . connection . dispose ( ) ;
@@ -475,11 +489,18 @@ class NativePythonFinderImpl implements NativePythonFinder {
475489 // Handle process exit - mark as exited so pending requests fail fast
476490 this . proc . on ( 'exit' , ( code , signal ) => {
477491 this . processExited = true ;
492+ const wasExpected = this . isRestarting || this . isDisposed ;
478493 if ( code !== 0 ) {
479494 this . outputChannel . error (
480495 `[pet] Python Environment Tools exited unexpectedly with code ${ code } , signal ${ signal } ` ,
481496 ) ;
482497 }
498+ sendTelemetryEvent ( EventNames . PET_PROCESS_EXIT , undefined , {
499+ exitCode : code ,
500+ signal : signal ?? null ,
501+ restartAttempt : this . restartAttempts ,
502+ wasExpected,
503+ } ) ;
483504 } ) ;
484505
485506 // Handle process errors (e.g., ENOENT if executable not found)
@@ -898,5 +919,7 @@ export async function createNativePythonFinder(
898919 api : PythonProjectApi ,
899920 context : ExtensionContext ,
900921) : Promise < NativePythonFinder > {
901- return new NativePythonFinderImpl ( outputChannel , await getNativePythonToolsPath ( ) , api , getCacheDirectory ( context ) ) ;
922+ const petPath = await getNativePythonToolsPath ( ) ;
923+ traceVerbose ( `[pet] Resolved pet binary path: ${ petPath } ` ) ;
924+ return new NativePythonFinderImpl ( outputChannel , petPath , api , getCacheDirectory ( context ) ) ;
902925}
0 commit comments