33import * as child_process from 'child_process' ;
44import { EventEmitter } from 'events' ;
55import * as path from 'path' ;
6- import {
7- ConfigurationChangeEvent , ConfigurationTarget , DiagnosticSeverity , Disposable , Uri ,
8- workspace , WorkspaceConfiguration
9- } from 'vscode' ;
6+ import { ConfigurationChangeEvent , ConfigurationTarget , DiagnosticSeverity , Disposable , Uri , WorkspaceConfiguration } from 'vscode' ;
7+ import '../common/extensions' ;
8+ import { IInterpreterAutoSeletionProxyService } from '../interpreter/autoSelection/types' ;
109import { sendTelemetryEvent } from '../telemetry' ;
1110import { COMPLETION_ADD_BRACKETS , FORMAT_ON_TYPE } from '../telemetry/constants' ;
11+ import { IWorkspaceService } from './application/types' ;
12+ import { WorkspaceService } from './application/workspace' ;
1213import { isTestExecution } from './constants' ;
1314import { IS_WINDOWS } from './platform/constants' ;
1415import {
@@ -57,21 +58,28 @@ export class PythonSettings extends EventEmitter implements IPythonSettings {
5758 private disposables : Disposable [ ] = [ ] ;
5859 // tslint:disable-next-line:variable-name
5960 private _pythonPath = '' ;
61+ private readonly workspace : IWorkspaceService ;
6062
61- constructor ( workspaceFolder ?: Uri ) {
63+ constructor ( workspaceFolder : Uri | undefined , private readonly InterpreterAutoSelectionService : IInterpreterAutoSeletionProxyService ,
64+ workspace ?: IWorkspaceService ) {
6265 super ( ) ;
66+ this . workspace = workspace || new WorkspaceService ( ) ;
6367 this . workspaceRoot = workspaceFolder ? workspaceFolder : Uri . file ( __dirname ) ;
6468 this . initialize ( ) ;
6569 }
6670 // tslint:disable-next-line:function-name
67- public static getInstance ( resource ?: Uri ) : PythonSettings {
68- const workspaceFolderUri = PythonSettings . getSettingsUriAndTarget ( resource ) . uri ;
71+ public static getInstance ( resource : Uri | undefined , interpreterAutoSelectionService : IInterpreterAutoSeletionProxyService ,
72+ workspace ?: IWorkspaceService ) : PythonSettings {
73+ workspace = workspace || new WorkspaceService ( ) ;
74+ const workspaceFolderUri = PythonSettings . getSettingsUriAndTarget ( resource , workspace ) . uri ;
6975 const workspaceFolderKey = workspaceFolderUri ? workspaceFolderUri . fsPath : '' ;
7076
7177 if ( ! PythonSettings . pythonSettings . has ( workspaceFolderKey ) ) {
72- const settings = new PythonSettings ( workspaceFolderUri ) ;
78+ const settings = new PythonSettings ( workspaceFolderUri , interpreterAutoSelectionService , workspace ) ;
7379 PythonSettings . pythonSettings . set ( workspaceFolderKey , settings ) ;
74- const config = workspace . getConfiguration ( 'editor' , resource ? resource : null ) ;
80+ // Pass null to avoid VSC from complaining about not passing in a value.
81+ // tslint:disable-next-line:no-any
82+ const config = workspace . getConfiguration ( 'editor' , resource ? resource : null as any ) ;
7583 const formatOnType = config ? config . get ( 'formatOnType' , false ) : false ;
7684 sendTelemetryEvent ( COMPLETION_ADD_BRACKETS , undefined , { enabled : settings . autoComplete ? settings . autoComplete . addBrackets : false } ) ;
7785 sendTelemetryEvent ( FORMAT_ON_TYPE , undefined , { enabled : formatOnType } ) ;
@@ -81,7 +89,8 @@ export class PythonSettings extends EventEmitter implements IPythonSettings {
8189 }
8290
8391 // tslint:disable-next-line:type-literal-delimiter
84- public static getSettingsUriAndTarget ( resource ?: Uri ) : { uri : Uri | undefined , target : ConfigurationTarget } {
92+ public static getSettingsUriAndTarget ( resource : Uri | undefined , workspace ?: IWorkspaceService ) : { uri : Uri | undefined , target : ConfigurationTarget } {
93+ workspace = workspace || new WorkspaceService ( ) ;
8594 const workspaceFolder = resource ? workspace . getWorkspaceFolder ( resource ) : undefined ;
8695 let workspaceFolderUri : Uri | undefined = workspaceFolder ? workspaceFolder . uri : undefined ;
8796
@@ -99,21 +108,29 @@ export class PythonSettings extends EventEmitter implements IPythonSettings {
99108 throw new Error ( 'Dispose can only be called from unit tests' ) ;
100109 }
101110 // tslint:disable-next-line:no-void-expression
102- PythonSettings . pythonSettings . forEach ( item => item . dispose ( ) ) ;
111+ PythonSettings . pythonSettings . forEach ( item => item && item . dispose ( ) ) ;
103112 PythonSettings . pythonSettings . clear ( ) ;
104113 }
105114 public dispose ( ) {
106115 // tslint:disable-next-line:no-unsafe-any
107- this . disposables . forEach ( disposable => disposable . dispose ( ) ) ;
116+ this . disposables . forEach ( disposable => disposable && disposable . dispose ( ) ) ;
108117 this . disposables = [ ] ;
109118 }
110119 // tslint:disable-next-line:cyclomatic-complexity max-func-body-length
111- public update ( pythonSettings : WorkspaceConfiguration ) {
120+ protected update ( pythonSettings : WorkspaceConfiguration ) {
112121 const workspaceRoot = this . workspaceRoot . fsPath ;
113122 const systemVariables : SystemVariables = new SystemVariables ( this . workspaceRoot ? this . workspaceRoot . fsPath : undefined ) ;
114123
115124 // tslint:disable-next-line:no-backbone-get-set-outside-model no-non-null-assertion
116125 this . pythonPath = systemVariables . resolveAny ( pythonSettings . get < string > ( 'pythonPath' ) ) ! ;
126+ // If user has defined a custom value, use it else try to get the best interpreter ourselves.
127+ if ( this . pythonPath . length === 0 || this . pythonPath === 'python' ) {
128+ const autoSelectedPythonInterpreter = this . InterpreterAutoSelectionService . getAutoSelectedInterpreter ( this . workspaceRoot ) ;
129+ if ( autoSelectedPythonInterpreter ) {
130+ this . InterpreterAutoSelectionService . setWorkspaceInterpreter ( this . workspaceRoot , autoSelectedPythonInterpreter ) . ignoreErrors ( ) ;
131+ }
132+ this . pythonPath = autoSelectedPythonInterpreter ? autoSelectedPythonInterpreter . path : this . pythonPath ;
133+ }
117134 this . pythonPath = getAbsolutePath ( this . pythonPath , workspaceRoot ) ;
118135 // tslint:disable-next-line:no-backbone-get-set-outside-model no-non-null-assertion
119136 this . venvPath = systemVariables . resolveAny ( pythonSettings . get < string > ( 'venvPath' ) ) ! ;
@@ -342,25 +359,31 @@ export class PythonSettings extends EventEmitter implements IPythonSettings {
342359 // Add support for specifying just the directory where the python executable will be located.
343360 // E.g. virtual directory name.
344361 try {
345- this . _pythonPath = getPythonExecutable ( value ) ;
362+ this . _pythonPath = this . getPythonExecutable ( value ) ;
346363 } catch ( ex ) {
347364 this . _pythonPath = value ;
348365 }
349366 }
367+ protected getPythonExecutable ( pythonPath : string ) {
368+ return getPythonExecutable ( pythonPath ) ;
369+ }
350370 protected initialize ( ) : void {
351- this . disposables . push ( workspace . onDidChangeConfiguration ( ( event : ConfigurationChangeEvent ) => {
352- if ( event . affectsConfiguration ( 'python' ) )
353- {
354- const currentConfig = workspace . getConfiguration ( 'python' , this . workspaceRoot ) ;
355- this . update ( currentConfig ) ;
356-
357- // If workspace config changes, then we could have a cascading effect of on change events.
358- // Let's defer the change notification.
359- setTimeout ( ( ) => this . emit ( 'change' ) , 1 ) ;
371+ const onDidChange = ( ) => {
372+ const currentConfig = this . workspace . getConfiguration ( 'python' , this . workspaceRoot ) ;
373+ this . update ( currentConfig ) ;
374+
375+ // If workspace config changes, then we could have a cascading effect of on change events.
376+ // Let's defer the change notification.
377+ setTimeout ( ( ) => this . emit ( 'change' ) , 1 ) ;
378+ } ;
379+ this . disposables . push ( this . InterpreterAutoSelectionService . onDidChangeAutoSelectedInterpreter ( onDidChange . bind ( this ) ) ) ;
380+ this . disposables . push ( this . workspace . onDidChangeConfiguration ( ( event : ConfigurationChangeEvent ) => {
381+ if ( event . affectsConfiguration ( 'python' ) ) {
382+ onDidChange ( ) ;
360383 }
361384 } ) ) ;
362385
363- const initialConfig = workspace . getConfiguration ( 'python' , this . workspaceRoot ) ;
386+ const initialConfig = this . workspace . getConfiguration ( 'python' , this . workspaceRoot ) ;
364387 if ( initialConfig ) {
365388 this . update ( initialConfig ) ;
366389 }
0 commit comments