@@ -114,6 +114,16 @@ class NativePythonFinderImpl extends DisposableBase implements NativePythonFinde
114114
115115 private readonly suppressErrorNotification : IPersistentStorage < boolean > ;
116116
117+ /**
118+ * Tracks whether the internal JSON-RPC connection has been closed.
119+ * This can happen independently of the finder being disposed.
120+ */
121+ private _connectionClosed = false ;
122+
123+ public get isConnectionClosed ( ) : boolean {
124+ return this . _connectionClosed ;
125+ }
126+
117127 constructor ( private readonly cacheDirectory ?: Uri , private readonly context ?: IExtensionContext ) {
118128 super ( ) ;
119129 this . suppressErrorNotification = this . context
@@ -135,14 +145,21 @@ class NativePythonFinderImpl extends DisposableBase implements NativePythonFinde
135145 }
136146
137147 async * refresh ( options ?: NativePythonEnvironmentKind | Uri [ ] ) : AsyncIterable < NativeEnvInfo > {
148+ this . outputChannel . info (
149+ `refresh() called: firstRefreshResults=${ ! ! this . firstRefreshResults } , connectionClosed=${
150+ this . _connectionClosed
151+ } , isDisposed=${ this . isDisposed } `,
152+ ) ;
138153 if ( this . firstRefreshResults ) {
139154 // If this is the first time we are refreshing,
140155 // Then get the results from the first refresh.
141156 // Those would have started earlier and cached in memory.
157+ this . outputChannel . info ( 'Using firstRefreshResults' ) ;
142158 const results = this . firstRefreshResults ( ) ;
143159 this . firstRefreshResults = undefined ;
144160 yield * results ;
145161 } else {
162+ this . outputChannel . info ( 'Calling doRefresh' ) ;
146163 const result = this . doRefresh ( options ) ;
147164 let completed = false ;
148165 void result . completed . finally ( ( ) => {
@@ -298,6 +315,8 @@ class NativePythonFinderImpl extends DisposableBase implements NativePythonFinde
298315 sendNativeTelemetry ( data , this . initialRefreshMetrics ) ,
299316 ) ,
300317 connection . onClose ( ( ) => {
318+ this . outputChannel . info ( 'JSON-RPC connection closed, marking connection as closed' ) ;
319+ this . _connectionClosed = true ;
301320 disposables . forEach ( ( d ) => d . dispose ( ) ) ;
302321 } ) ,
303322 ) ;
@@ -535,7 +554,15 @@ export function getNativePythonFinder(context?: IExtensionContext): NativePython
535554}
536555
537556function isFinderDisposed ( finder : NativePythonFinder ) : boolean {
538- return 'isDisposed' in finder && Boolean ( ( finder as { isDisposed ?: boolean } ) . isDisposed ) ;
557+ const finderImpl = finder as { isDisposed ?: boolean ; isConnectionClosed ?: boolean } ;
558+ const disposed = Boolean ( finderImpl . isDisposed ) ;
559+ const connectionClosed = Boolean ( finderImpl . isConnectionClosed ) ;
560+ if ( disposed || connectionClosed ) {
561+ traceError (
562+ `[NativePythonFinder] Finder needs recreation: isDisposed=${ disposed } , isConnectionClosed=${ connectionClosed } ` ,
563+ ) ;
564+ }
565+ return disposed || connectionClosed ;
539566}
540567
541568export function getCacheDirectory ( context : IExtensionContext ) : Uri {
@@ -546,3 +573,14 @@ export async function clearCacheDirectory(context: IExtensionContext): Promise<v
546573 const cacheDirectory = getCacheDirectory ( context ) ;
547574 await fs . emptyDir ( cacheDirectory . fsPath ) . catch ( noop ) ;
548575}
576+
577+ /**
578+ * Clears the singleton finder instance. For testing purposes only.
579+ * @internal
580+ */
581+ export function clearNativePythonFinder ( ) : void {
582+ if ( _finder ) {
583+ _finder . dispose ( ) ;
584+ _finder = undefined ;
585+ }
586+ }
0 commit comments