3333using Microsoft . Python . Core . Diagnostics ;
3434using Microsoft . Python . Core . IO ;
3535using Microsoft . Python . Core . OS ;
36+ using Microsoft . Python . Core . Services ;
3637
3738namespace Microsoft . Python . Analysis . Modules . Resolution {
3839 internal sealed class MainModuleResolution : ModuleResolutionBase , IModuleManagement {
3940 private readonly ConcurrentDictionary < string , IPythonModule > _specialized = new ConcurrentDictionary < string , IPythonModule > ( ) ;
41+ private readonly IUIService _ui ;
4042 private IRunningDocumentTable _rdt ;
4143
4244 private ImmutableArray < string > _userPaths = ImmutableArray < string > . Empty ;
4345
4446 public MainModuleResolution ( string root , IServiceContainer services )
45- : base ( root , services ) { }
47+ : base ( root , services ) {
4648
47- internal IBuiltinsPythonModule CreateBuiltinsModule ( ) {
48- if ( BuiltinsModule == null ) {
49- // Initialize built-in
50- var moduleName = BuiltinTypeId . Unknown . GetModuleName ( _interpreter . LanguageVersion ) ;
51-
52- StubCache = _services . GetService < IStubCache > ( ) ;
53- var modulePath = StubCache . GetCacheFilePath ( _interpreter . Configuration . InterpreterPath ) ;
54-
55- var b = new BuiltinsPythonModule ( moduleName , modulePath , _services ) ;
56- BuiltinsModule = b ;
57- Modules [ BuiltinModuleName ] = new ModuleRef ( b ) ;
58- }
59- return BuiltinsModule ;
49+ _ui = services . GetService < IUIService > ( ) ;
6050 }
51+
52+ public string BuiltinModuleName => BuiltinTypeId . Unknown . GetModuleName ( Interpreter . LanguageVersion ) ;
6153
62- internal async Task InitializeAsync ( CancellationToken cancellationToken = default ) {
63- await ReloadAsync ( cancellationToken ) ;
64- cancellationToken . ThrowIfCancellationRequested ( ) ;
65- }
54+ public IBuiltinsPythonModule BuiltinsModule { get ; private set ; }
6655
6756 protected override IPythonModule CreateModule ( string name ) {
6857 var moduleImport = CurrentPathResolver . GetModuleImportFromModuleName ( name ) ;
6958 if ( moduleImport == null ) {
70- _log ? . Log ( TraceEventType . Verbose , "Import not found: " , name ) ;
59+ Log ? . Log ( TraceEventType . Verbose , "Import not found: " , name ) ;
7160 return null ;
7261 }
7362
@@ -83,7 +72,7 @@ protected override IPythonModule CreateModule(string name) {
8372 // First check stub next to the module.
8473 if ( ! TryCreateModuleStub ( name , moduleImport . ModulePath , out var stub ) ) {
8574 // If nothing found, try Typeshed.
86- stub = _interpreter . TypeshedResolution . GetOrLoadModule ( moduleImport . IsBuiltin ? name : moduleImport . FullName ) ;
75+ stub = Interpreter . TypeshedResolution . GetOrLoadModule ( moduleImport . IsBuiltin ? name : moduleImport . FullName ) ;
8776 }
8877
8978 // If stub is created and its path equals to module, return that stub as module
@@ -92,16 +81,16 @@ protected override IPythonModule CreateModule(string name) {
9281 }
9382
9483 if ( moduleImport . IsBuiltin ) {
95- _log ? . Log ( TraceEventType . Verbose , "Create built-in compiled (scraped) module: " , name , Configuration . InterpreterPath ) ;
96- return new CompiledBuiltinPythonModule ( name , stub , _services ) ;
84+ Log ? . Log ( TraceEventType . Verbose , "Create built-in compiled (scraped) module: " , name , Configuration . InterpreterPath ) ;
85+ return new CompiledBuiltinPythonModule ( name , stub , Services ) ;
9786 }
9887
9988 if ( moduleImport . IsCompiled ) {
100- _log ? . Log ( TraceEventType . Verbose , "Create compiled (scraped): " , moduleImport . FullName , moduleImport . ModulePath , moduleImport . RootPath ) ;
101- return new CompiledPythonModule ( moduleImport . FullName , ModuleType . Compiled , moduleImport . ModulePath , stub , _services ) ;
89+ Log ? . Log ( TraceEventType . Verbose , "Create compiled (scraped): " , moduleImport . FullName , moduleImport . ModulePath , moduleImport . RootPath ) ;
90+ return new CompiledPythonModule ( moduleImport . FullName , ModuleType . Compiled , moduleImport . ModulePath , stub , Services ) ;
10291 }
10392
104- _log ? . Log ( TraceEventType . Verbose , "Import: " , moduleImport . FullName , moduleImport . ModulePath ) ;
93+ Log ? . Log ( TraceEventType . Verbose , "Import: " , moduleImport . FullName , moduleImport . ModulePath ) ;
10594 // Module inside workspace == user code.
10695
10796 var mco = new ModuleCreationOptions {
@@ -114,24 +103,22 @@ protected override IPythonModule CreateModule(string name) {
114103 return GetRdt ( ) . AddModule ( mco ) ;
115104 }
116105
117- private async Task < IReadOnlyList < PythonLibraryPath > > GetInterpreterSearchPathsAsync ( CancellationToken cancellationToken = default ) {
118- if ( ! _fs . FileExists ( Configuration . InterpreterPath ) ) {
119- _log ? . Log ( TraceEventType . Warning , "Interpreter does not exist:" , Configuration . InterpreterPath ) ;
106+ private async Task < ImmutableArray < PythonLibraryPath > > GetInterpreterSearchPathsAsync ( CancellationToken cancellationToken = default ) {
107+ if ( ! FileSystem . FileExists ( Configuration . InterpreterPath ) ) {
108+ Log ? . Log ( TraceEventType . Warning , "Interpreter does not exist:" , Configuration . InterpreterPath ) ;
120109 _ui ? . ShowMessageAsync ( Resources . InterpreterNotFound , TraceEventType . Error ) ;
121- return Array . Empty < PythonLibraryPath > ( ) ;
110+ return ImmutableArray < PythonLibraryPath > . Empty ;
122111 }
123112
124- _log ? . Log ( TraceEventType . Information , "GetCurrentSearchPaths" , Configuration . InterpreterPath ) ;
113+ Log ? . Log ( TraceEventType . Information , "GetCurrentSearchPaths" , Configuration . InterpreterPath ) ;
125114 try {
126- var fs = _services . GetService < IFileSystem > ( ) ;
127- var ps = _services . GetService < IProcessServices > ( ) ;
128- var paths = await PythonLibraryPath . GetSearchPathsAsync ( Configuration , fs , ps , cancellationToken ) ;
129- cancellationToken . ThrowIfCancellationRequested ( ) ;
130- return paths . ToArray ( ) ;
115+ var fs = Services . GetService < IFileSystem > ( ) ;
116+ var ps = Services . GetService < IProcessServices > ( ) ;
117+ return await PythonLibraryPath . GetSearchPathsAsync ( Configuration , fs , ps , cancellationToken ) ;
131118 } catch ( InvalidOperationException ex ) {
132- _log ? . Log ( TraceEventType . Warning , "Exception getting search paths" , ex ) ;
119+ Log ? . Log ( TraceEventType . Warning , "Exception getting search paths" , ex ) ;
133120 _ui ? . ShowMessageAsync ( Resources . ExceptionGettingSearchPaths , TraceEventType . Error ) ;
134- return Array . Empty < PythonLibraryPath > ( ) ;
121+ return ImmutableArray < PythonLibraryPath > . Empty ;
135122 }
136123 }
137124
@@ -157,8 +144,8 @@ public IPythonModule SpecializeModule(string name, Func<string, IPythonModule> s
157144 public IPythonModule GetSpecializedModule ( string name )
158145 => _specialized . TryGetValue ( name , out var module ) ? module : null ;
159146
160- internal async Task LoadBuiltinTypesAsync ( CancellationToken cancellationToken = default ) {
161- var analyzer = _services . GetService < IPythonAnalyzer > ( ) ;
147+ internal async Task AddBuiltinTypesToPathResolverAsync ( CancellationToken cancellationToken = default ) {
148+ var analyzer = Services . GetService < IPythonAnalyzer > ( ) ;
162149 await analyzer . GetAnalysisAsync ( BuiltinsModule , - 1 , cancellationToken ) ;
163150
164151 Check . InvalidOperation ( ! ( BuiltinsModule . Analysis is EmptyAnalysis ) , "After await" ) ;
@@ -172,26 +159,6 @@ internal async Task LoadBuiltinTypesAsync(CancellationToken cancellationToken =
172159 }
173160 }
174161
175- internal async Task ReloadSearchPaths ( CancellationToken cancellationToken = default ) {
176- var ps = _services . GetService < IProcessServices > ( ) ;
177-
178- var paths = await GetInterpreterSearchPathsAsync ( cancellationToken ) ;
179- var ( interpreterPaths , userPaths ) = PythonLibraryPath . ClassifyPaths ( Root , _fs , paths , Configuration . SearchPaths ) ;
180-
181- InterpreterPaths = interpreterPaths . Select ( p => p . Path ) ;
182- _userPaths = userPaths . Select ( p => p . Path ) ;
183-
184- _log ? . Log ( TraceEventType . Information , "Interpreter search paths:" ) ;
185- foreach ( var s in InterpreterPaths ) {
186- _log ? . Log ( TraceEventType . Information , $ " { s } ") ;
187- }
188-
189- _log ? . Log ( TraceEventType . Information , "User search paths:" ) ;
190- foreach ( var s in _userPaths ) {
191- _log ? . Log ( TraceEventType . Information , $ " { s } ") ;
192- }
193- }
194-
195162 public async Task ReloadAsync ( CancellationToken cancellationToken = default ) {
196163 foreach ( var uri in Modules
197164 . Where ( m => m . Value . Value ? . Name != BuiltinModuleName )
@@ -201,45 +168,78 @@ public async Task ReloadAsync(CancellationToken cancellationToken = default) {
201168 }
202169
203170 // Preserve builtins, they don't need to be reloaded since interpreter does not change.
204- if ( Modules . TryGetValue ( BuiltinModuleName , out var builtins ) ) {
205- Modules . Clear ( ) ;
206- Modules [ BuiltinModuleName ] = builtins ;
207- }
171+ var builtinsIsCreated = Modules . TryGetValue ( BuiltinModuleName , out var builtinsRef ) ;
172+ Modules . Clear ( ) ;
208173
209174 await ReloadSearchPaths ( cancellationToken ) ;
210175
211- PathResolver = new PathResolver ( _interpreter . LanguageVersion , Root , InterpreterPaths , _userPaths ) ;
176+ PathResolver = new PathResolver ( Interpreter . LanguageVersion , Root , InterpreterPaths , _userPaths ) ;
212177
213178 var addedRoots = new HashSet < string > { Root } ;
214179 addedRoots . UnionWith ( InterpreterPaths ) ;
215180 addedRoots . UnionWith ( _userPaths ) ;
216181 ReloadModulePaths ( addedRoots ) ;
182+
183+ if ( ! builtinsIsCreated ) {
184+ var builtinsModule = CreateBuiltinsModule ( Services , Interpreter , StubCache ) ;
185+ BuiltinsModule = builtinsModule ;
186+ builtinsRef = new ModuleRef ( builtinsModule ) ;
187+ }
188+
189+ Modules [ BuiltinModuleName ] = builtinsRef ;
190+ await AddBuiltinTypesToPathResolverAsync ( cancellationToken ) ;
191+ }
192+
193+ private static IBuiltinsPythonModule CreateBuiltinsModule ( IServiceContainer services , IPythonInterpreter interpreter , IStubCache stubCache ) {
194+ var moduleName = BuiltinTypeId . Unknown . GetModuleName ( interpreter . LanguageVersion ) ;
195+ var modulePath = stubCache . GetCacheFilePath ( interpreter . Configuration . InterpreterPath ) ;
196+ return new BuiltinsPythonModule ( moduleName , modulePath , services ) ;
197+ }
198+
199+ private async Task ReloadSearchPaths ( CancellationToken cancellationToken = default ) {
200+ var paths = await GetInterpreterSearchPathsAsync ( cancellationToken ) ;
201+ var ( interpreterPaths , userPaths ) = PythonLibraryPath . ClassifyPaths ( Root , FileSystem , paths , Configuration . SearchPaths ) ;
202+
203+ InterpreterPaths = interpreterPaths . Select ( p => p . Path ) ;
204+ _userPaths = userPaths . Select ( p => p . Path ) ;
205+
206+ if ( Log != null ) {
207+ Log . Log ( TraceEventType . Information , "Interpreter search paths:" ) ;
208+ foreach ( var s in InterpreterPaths ) {
209+ Log . Log ( TraceEventType . Information , $ " { s } ") ;
210+ }
211+
212+ Log . Log ( TraceEventType . Information , "User search paths:" ) ;
213+ foreach ( var s in _userPaths ) {
214+ Log . Log ( TraceEventType . Information , $ " { s } ") ;
215+ }
216+ }
217217 }
218218
219219 public bool TryAddModulePath ( in string path , in long fileSize , in bool allowNonRooted , out string fullModuleName )
220220 => PathResolver . TryAddModulePath ( path , fileSize , allowNonRooted , out fullModuleName ) ;
221221
222222 // For tests
223223 internal void AddUnimportableModule ( string moduleName )
224- => Modules [ moduleName ] = new ModuleRef ( new SentinelModule ( moduleName , _services ) ) ;
224+ => Modules [ moduleName ] = new ModuleRef ( new SentinelModule ( moduleName , Services ) ) ;
225225
226226 private bool TryCreateModuleStub ( string name , string modulePath , out IPythonModule module ) {
227227 // First check stub next to the module.
228228 if ( ! string . IsNullOrEmpty ( modulePath ) ) {
229229 var pyiPath = Path . ChangeExtension ( modulePath , "pyi" ) ;
230- if ( _fs . FileExists ( pyiPath ) ) {
231- module = new StubPythonModule ( name , pyiPath , false , _services ) ;
230+ if ( FileSystem . FileExists ( pyiPath ) ) {
231+ module = new StubPythonModule ( name , pyiPath , false , Services ) ;
232232 return true ;
233233 }
234234 }
235235
236236 // Try location of stubs that are in a separate folder next to the package.
237- var stubPath = CurrentPathResolver . GetPossibleModuleStubPaths ( name ) . FirstOrDefault ( p => _fs . FileExists ( p ) ) ;
238- module = ! string . IsNullOrEmpty ( stubPath ) ? new StubPythonModule ( name , stubPath , false , _services ) : null ;
237+ var stubPath = CurrentPathResolver . GetPossibleModuleStubPaths ( name ) . FirstOrDefault ( p => FileSystem . FileExists ( p ) ) ;
238+ module = ! string . IsNullOrEmpty ( stubPath ) ? new StubPythonModule ( name , stubPath , false , Services ) : null ;
239239 return module != null ;
240240 }
241241
242242 private IRunningDocumentTable GetRdt ( )
243- => _rdt ?? ( _rdt = _services . GetService < IRunningDocumentTable > ( ) ) ;
243+ => _rdt ?? ( _rdt = Services . GetService < IRunningDocumentTable > ( ) ) ;
244244 }
245245}
0 commit comments