@@ -10,33 +10,34 @@ import { URL } from 'url';
1010import  *  as  uuid  from  'uuid/v4' ; 
1111import  {  CancellationToken ,  Disposable  }  from  'vscode-jsonrpc' ; 
1212
13- import  {  Cancellation ,  CancellationError  }  from  '../common/cancellation' ; 
14- import  {  IS_WINDOWS  }  from  '../common/platform/constants' ; 
15- import  {  IFileSystem ,  TemporaryDirectory  }  from  '../common/platform/types' ; 
13+ import  {  Cancellation ,  CancellationError  }  from  '../../ common/cancellation' ; 
14+ import  {  IS_WINDOWS  }  from  '../../ common/platform/constants' ; 
15+ import  {  IFileSystem ,  TemporaryDirectory  }  from  '../../ common/platform/types' ; 
1616import  { 
1717 ExecutionResult , 
1818 IProcessService , 
1919 IProcessServiceFactory , 
2020 IPythonExecutionFactory , 
2121 ObservableExecutionResult , 
2222 SpawnOptions 
23- }  from  '../common/process/types' ; 
24- import  {  IAsyncDisposableRegistry ,  IDisposableRegistry ,  ILogger  }  from  '../common/types' ; 
25- import  *  as  localize  from  '../common/utils/localize' ; 
26- import  {  noop  }  from  '../common/utils/misc' ; 
27- import  {  EXTENSION_ROOT_DIR  }  from  '../constants' ; 
23+ }  from  '../../ common/process/types' ; 
24+ import  {  IAsyncDisposableRegistry ,  IDisposableRegistry ,  ILogger  }  from  '../../ common/types' ; 
25+ import  *  as  localize  from  '../../ common/utils/localize' ; 
26+ import  {  noop  }  from  '../../ common/utils/misc' ; 
27+ import  {  EXTENSION_ROOT_DIR  }  from  '../../ constants' ; 
2828import  { 
2929 ICondaService , 
3030 IInterpreterService , 
3131 IKnownSearchPathsForInterpreters , 
3232 InterpreterType , 
3333 PythonInterpreter 
34- }  from  '../interpreter/contracts' ; 
35- import  {  IServiceContainer  }  from  '../ioc/types' ; 
36- import  {  captureTelemetry  }  from  '../telemetry' ; 
37- import  {  Telemetry  }  from  './constants' ; 
34+ }  from  '../../ interpreter/contracts' ; 
35+ import  {  IServiceContainer  }  from  '../../ ioc/types' ; 
36+ import  {  captureTelemetry  }  from  '../../ telemetry' ; 
37+ import  {  Telemetry  }  from  '.. /constants' ; 
3838import  {  JupyterConnection ,  JupyterServerInfo  }  from  './jupyterConnection' ; 
39- import  {  IConnection ,  IJupyterExecution ,  IJupyterKernelSpec ,  INotebookServer  }  from  './types' ; 
39+ import  {  IConnection ,  IJupyterExecution ,  IJupyterKernelSpec ,  INotebookServer ,  IJupyterSessionManager  }  from  '../types' ; 
40+ import  {  JupyterKernelSpec  }  from  './jupyterKernelSpec' ; 
4041
4142const  CheckJupyterRegEx  =  IS_WINDOWS  ? / ^ j u p y t e r ? \. e x e $ / / ^ j u p y t e r ? $ / ; 
4243const  NotebookCommand  =  'notebook' ; 
@@ -45,33 +46,6 @@ const KernelSpecCommand = 'kernelspec';
4546const  KernelCreateCommand  =  'ipykernel' ; 
4647const  PyKernelOutputRegEx  =  / .* \s + ( .+ ) $ / m; 
4748const  KernelSpecOutputRegEx  =  / ^ \s * ( \S + ) \s + ( \S + ) $ / ; 
48- const  IsGuidRegEx  =  / ^ [ 0 - 9 a - f ] { 8 } - [ 0 - 9 a - f ] { 4 } - [ 1 - 5 ] [ 0 - 9 a - f ] { 3 } - [ 8 9 a b ] [ 0 - 9 a - f ] { 3 } - [ 0 - 9 a - f ] { 12 } $ / i; 
49- 
50- class  JupyterKernelSpec  implements  IJupyterKernelSpec  { 
51-  public  name : string ; 
52-  public  language : string ; 
53-  public  path : string ; 
54-  public  specFile : string  |  undefined ; 
55-  constructor ( specModel : Kernel . ISpecModel ,  file ?: string )  { 
56-  this . name  =  specModel . name ; 
57-  this . language  =  specModel . language ; 
58-  this . path  =  specModel . argv . length  >  0  ? specModel . argv [ 0 ]  : '' ; 
59-  this . specFile  =  file ; 
60-  } 
61-  public  dispose  =  async  ( )  =>  { 
62-  if  ( this . specFile  && 
63-  IsGuidRegEx . test ( path . basename ( path . dirname ( this . specFile ) ) ) )  { 
64-  // There is more than one location for the spec file directory 
65-  // to be cleaned up. If one fails, the other likely deleted it already. 
66-  try  { 
67-  await  fs . remove ( path . dirname ( this . specFile ) ) ; 
68-  }  catch  { 
69-  noop ( ) ; 
70-  } 
71-  this . specFile  =  undefined ; 
72-  } 
73-  } 
74- } 
7549
7650// JupyterCommand objects represent some process that can be launched that should be guaranteed to work because it 
7751// was found by testing it previously 
@@ -155,21 +129,22 @@ export class JupyterExecution implements IJupyterExecution, Disposable {
155129 private  usablePythonInterpreter : PythonInterpreter  |  undefined ; 
156130
157131 constructor ( @inject ( IPythonExecutionFactory )  private  executionFactory : IPythonExecutionFactory , 
158-  @inject ( ICondaService )  private  condaService : ICondaService , 
159-  @inject ( IInterpreterService )  private  interpreterService : IInterpreterService , 
160-  @inject ( IProcessServiceFactory )  private  processServiceFactory : IProcessServiceFactory , 
161-  @inject ( IKnownSearchPathsForInterpreters )  private  knownSearchPaths : IKnownSearchPathsForInterpreters , 
162-  @inject ( ILogger )  private  logger : ILogger , 
163-  @inject ( IDisposableRegistry )  private  disposableRegistry : IDisposableRegistry , 
164-  @inject ( IAsyncDisposableRegistry )  private  asyncRegistry : IAsyncDisposableRegistry , 
165-  @inject ( IFileSystem )  private  fileSystem : IFileSystem , 
166-  @inject ( IServiceContainer )  private  serviceContainer : IServiceContainer )  { 
132+  @inject ( ICondaService )  private  condaService : ICondaService , 
133+  @inject ( IInterpreterService )  private  interpreterService : IInterpreterService , 
134+  @inject ( IProcessServiceFactory )  private  processServiceFactory : IProcessServiceFactory , 
135+  @inject ( IKnownSearchPathsForInterpreters )  private  knownSearchPaths : IKnownSearchPathsForInterpreters , 
136+  @inject ( ILogger )  private  logger : ILogger , 
137+  @inject ( IDisposableRegistry )  private  disposableRegistry : IDisposableRegistry , 
138+  @inject ( IAsyncDisposableRegistry )  private  asyncRegistry : IAsyncDisposableRegistry , 
139+  @inject ( IFileSystem )  private  fileSystem : IFileSystem , 
140+  @inject ( IJupyterSessionManager )  private  sessionManager : IJupyterSessionManager , 
141+  @inject ( IServiceContainer )  private  serviceContainer : IServiceContainer )  { 
167142 this . processServicePromise  =  this . processServiceFactory . create ( ) ; 
168-  this . disposableRegistry . push ( this . interpreterService . onDidChangeInterpreter ( this . onSettingsChanged ) ) ; 
143+  this . disposableRegistry . push ( this . interpreterService . onDidChangeInterpreter ( ( )   =>   this . onSettingsChanged ( ) ) ) ; 
169144 this . disposableRegistry . push ( this ) ; 
170145 } 
171146
172-  public  dispose   =   ( )   =>  { 
147+  public  dispose ( )  { 
173148 // Clear our usableJupyterInterpreter 
174149 this . usablePythonInterpreter  =  undefined ; 
175150 this . commands  =  { } ; 
@@ -241,7 +216,6 @@ export class JupyterExecution implements IJupyterExecution, Disposable {
241216
242217 // Try to connect to our jupyter process 
243218 const  result  =  this . serviceContainer . get < INotebookServer > ( INotebookServer ) ; 
244-  this . disposableRegistry . push ( result ) ; 
245219 await  result . connect ( connection ,  kernelSpec ,  cancelToken ,  workingDir ) ; 
246220 return  result ; 
247221 }  catch  ( err )  { 
@@ -298,7 +272,7 @@ export class JupyterExecution implements IJupyterExecution, Disposable {
298272 } 
299273
300274 // Now enumerate them again 
301-  const  enumerator  =  connection  ? ( )  =>  this . getActiveKernelSpecs ( connection )  : ( )  =>  this . enumerateSpecs ( cancelToken ) ; 
275+  const  enumerator  =  connection  ? ( )  =>  this . sessionManager . getActiveKernelSpecs ( connection )  : ( )  =>  this . enumerateSpecs ( cancelToken ) ; 
302276
303277 // Then find our match 
304278 return  this . findSpecMatch ( enumerator ) ; 
@@ -365,8 +339,10 @@ export class JupyterExecution implements IJupyterExecution, Disposable {
365339 const  launchResult  =  await  notebookCommand . execObservable ( args ,  {  throwOnStdErr : false ,  encoding : 'utf8' ,  token : cancelToken  } ) ; 
366340
367341 // Make sure this process gets cleaned up. We might be canceled before the connection finishes. 
368-  if  ( launchResult )  { 
369-  this . asyncRegistry . push ( {  dispose : ( )  =>  Promise . resolve ( launchResult . dispose ( ) )  } ) ; 
342+  if  ( launchResult  &&  cancelToken )  { 
343+  cancelToken . onCancellationRequested ( ( )  =>  { 
344+  launchResult . dispose ( ) ; 
345+  } ) ; 
370346 } 
371347
372348 // Wait for the connection information on this result 
@@ -475,10 +451,10 @@ export class JupyterExecution implements IJupyterExecution, Disposable {
475451 return  undefined ; 
476452 } 
477453
478-  private  onSettingsChanged   =   ( ) :  Promise < void >   =>  { 
454+  private  onSettingsChanged ( )  { 
479455 // Do the same thing as dispose so that we regenerate 
480456 // all of our commands 
481-  return   Promise . resolve ( this . dispose ( ) ) ; 
457+  this . dispose ( ) ; 
482458 } 
483459
484460 private  async  addMatchingSpec ( bestInterpreter : PythonInterpreter ,  cancelToken ?: CancellationToken ) : Promise < void >  { 
@@ -684,32 +660,7 @@ export class JupyterExecution implements IJupyterExecution, Disposable {
684660 return  bestSpec ; 
685661 } 
686662
687-  private  getActiveKernelSpecs  =  async  ( connection : IConnection ) : Promise < IJupyterKernelSpec [ ] >  =>  { 
688-  // Use our connection to create a session manager 
689-  const  serverSettings  =  ServerConnection . makeSettings ( 
690-  { 
691-  baseUrl : connection . baseUrl , 
692-  token : connection . token , 
693-  pageUrl : '' , 
694-  // A web socket is required to allow token authentication (what if there is no token authentication?) 
695-  wsUrl : connection . baseUrl . replace ( 'http' ,  'ws' ) , 
696-  init : {  cache : 'no-store' ,  credentials : 'same-origin'  } 
697-  } ) ; 
698-  const  sessionManager  =  new  SessionManager ( {  serverSettings : serverSettings  } ) ; 
699- 
700-  // Ask the session manager to refresh its list of kernel specs. 
701-  await  sessionManager . refreshSpecs ( ) ; 
702- 
703-  // Enumerate all of the kernel specs, turning each into a JupyterKernelSpec 
704-  const  kernelspecs  =  sessionManager . specs  &&  sessionManager . specs . kernelspecs  ? sessionManager . specs . kernelspecs  : { } ; 
705-  const  keys  =  Object . keys ( kernelspecs ) ; 
706-  return  keys . map ( k  =>  { 
707-  const  spec  =  kernelspecs [ k ] ; 
708-  return  new  JupyterKernelSpec ( spec ) ; 
709-  } ) ; 
710-  } 
711- 
712-  private  async  readSpec ( kernelSpecOutputLine : string ) : Promise < JupyterKernelSpec  |  undefined >  { 
663+  private  async  readSpec ( kernelSpecOutputLine : string )  : Promise < JupyterKernelSpec  |  undefined >  { 
713664 const  match  =  KernelSpecOutputRegEx . exec ( kernelSpecOutputLine ) ; 
714665 if  ( match  &&  match  !==  null  &&  match . length  >  2 )  { 
715666 // Second match should be our path to the kernel spec 
0 commit comments