33
33
using Microsoft . Python . Core . Diagnostics ;
34
34
using Microsoft . Python . Core . IO ;
35
35
using Microsoft . Python . Core . OS ;
36
+ using Microsoft . Python . Core . Services ;
36
37
37
38
namespace Microsoft . Python . Analysis . Modules . Resolution {
38
39
internal sealed class MainModuleResolution : ModuleResolutionBase , IModuleManagement {
39
40
private readonly ConcurrentDictionary < string , IPythonModule > _specialized = new ConcurrentDictionary < string , IPythonModule > ( ) ;
41
+ private readonly IUIService _ui ;
40
42
private IRunningDocumentTable _rdt ;
41
43
42
44
private ImmutableArray < string > _userPaths = ImmutableArray < string > . Empty ;
43
45
44
46
public MainModuleResolution ( string root , IServiceContainer services )
45
- : base ( root , services ) { }
47
+ : base ( root , services ) {
46
48
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 > ( ) ;
60
50
}
51
+
52
+ public string BuiltinModuleName => BuiltinTypeId . Unknown . GetModuleName ( Interpreter . LanguageVersion ) ;
61
53
62
- internal async Task InitializeAsync ( CancellationToken cancellationToken = default ) {
63
- await ReloadAsync ( cancellationToken ) ;
64
- cancellationToken . ThrowIfCancellationRequested ( ) ;
65
- }
54
+ public IBuiltinsPythonModule BuiltinsModule { get ; private set ; }
66
55
67
56
protected override IPythonModule CreateModule ( string name ) {
68
57
var moduleImport = CurrentPathResolver . GetModuleImportFromModuleName ( name ) ;
69
58
if ( moduleImport == null ) {
70
- _log ? . Log ( TraceEventType . Verbose , "Import not found: " , name ) ;
59
+ Log ? . Log ( TraceEventType . Verbose , "Import not found: " , name ) ;
71
60
return null ;
72
61
}
73
62
@@ -83,7 +72,7 @@ protected override IPythonModule CreateModule(string name) {
83
72
// First check stub next to the module.
84
73
if ( ! TryCreateModuleStub ( name , moduleImport . ModulePath , out var stub ) ) {
85
74
// 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 ) ;
87
76
}
88
77
89
78
// 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) {
92
81
}
93
82
94
83
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 ) ;
97
86
}
98
87
99
88
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 ) ;
102
91
}
103
92
104
- _log ? . Log ( TraceEventType . Verbose , "Import: " , moduleImport . FullName , moduleImport . ModulePath ) ;
93
+ Log ? . Log ( TraceEventType . Verbose , "Import: " , moduleImport . FullName , moduleImport . ModulePath ) ;
105
94
// Module inside workspace == user code.
106
95
107
96
var mco = new ModuleCreationOptions {
@@ -114,24 +103,22 @@ protected override IPythonModule CreateModule(string name) {
114
103
return GetRdt ( ) . AddModule ( mco ) ;
115
104
}
116
105
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 ) ;
120
109
_ui ? . ShowMessageAsync ( Resources . InterpreterNotFound , TraceEventType . Error ) ;
121
- return Array . Empty < PythonLibraryPath > ( ) ;
110
+ return ImmutableArray < PythonLibraryPath > . Empty ;
122
111
}
123
112
124
- _log ? . Log ( TraceEventType . Information , "GetCurrentSearchPaths" , Configuration . InterpreterPath ) ;
113
+ Log ? . Log ( TraceEventType . Information , "GetCurrentSearchPaths" , Configuration . InterpreterPath ) ;
125
114
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 ) ;
131
118
} catch ( InvalidOperationException ex ) {
132
- _log ? . Log ( TraceEventType . Warning , "Exception getting search paths" , ex ) ;
119
+ Log ? . Log ( TraceEventType . Warning , "Exception getting search paths" , ex ) ;
133
120
_ui ? . ShowMessageAsync ( Resources . ExceptionGettingSearchPaths , TraceEventType . Error ) ;
134
- return Array . Empty < PythonLibraryPath > ( ) ;
121
+ return ImmutableArray < PythonLibraryPath > . Empty ;
135
122
}
136
123
}
137
124
@@ -157,8 +144,8 @@ public IPythonModule SpecializeModule(string name, Func<string, IPythonModule> s
157
144
public IPythonModule GetSpecializedModule ( string name )
158
145
=> _specialized . TryGetValue ( name , out var module ) ? module : null ;
159
146
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 > ( ) ;
162
149
await analyzer . GetAnalysisAsync ( BuiltinsModule , - 1 , cancellationToken ) ;
163
150
164
151
Check . InvalidOperation ( ! ( BuiltinsModule . Analysis is EmptyAnalysis ) , "After await" ) ;
@@ -172,26 +159,6 @@ internal async Task LoadBuiltinTypesAsync(CancellationToken cancellationToken =
172
159
}
173
160
}
174
161
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
-
195
162
public async Task ReloadAsync ( CancellationToken cancellationToken = default ) {
196
163
foreach ( var uri in Modules
197
164
. Where ( m => m . Value . Value ? . Name != BuiltinModuleName )
@@ -201,45 +168,78 @@ public async Task ReloadAsync(CancellationToken cancellationToken = default) {
201
168
}
202
169
203
170
// 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 ( ) ;
208
173
209
174
await ReloadSearchPaths ( cancellationToken ) ;
210
175
211
- PathResolver = new PathResolver ( _interpreter . LanguageVersion , Root , InterpreterPaths , _userPaths ) ;
176
+ PathResolver = new PathResolver ( Interpreter . LanguageVersion , Root , InterpreterPaths , _userPaths ) ;
212
177
213
178
var addedRoots = new HashSet < string > { Root } ;
214
179
addedRoots . UnionWith ( InterpreterPaths ) ;
215
180
addedRoots . UnionWith ( _userPaths ) ;
216
181
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
+ }
217
217
}
218
218
219
219
public bool TryAddModulePath ( in string path , in long fileSize , in bool allowNonRooted , out string fullModuleName )
220
220
=> PathResolver . TryAddModulePath ( path , fileSize , allowNonRooted , out fullModuleName ) ;
221
221
222
222
// For tests
223
223
internal void AddUnimportableModule ( string moduleName )
224
- => Modules [ moduleName ] = new ModuleRef ( new SentinelModule ( moduleName , _services ) ) ;
224
+ => Modules [ moduleName ] = new ModuleRef ( new SentinelModule ( moduleName , Services ) ) ;
225
225
226
226
private bool TryCreateModuleStub ( string name , string modulePath , out IPythonModule module ) {
227
227
// First check stub next to the module.
228
228
if ( ! string . IsNullOrEmpty ( modulePath ) ) {
229
229
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 ) ;
232
232
return true ;
233
233
}
234
234
}
235
235
236
236
// 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 ;
239
239
return module != null ;
240
240
}
241
241
242
242
private IRunningDocumentTable GetRdt ( )
243
- => _rdt ?? ( _rdt = _services . GetService < IRunningDocumentTable > ( ) ) ;
243
+ => _rdt ?? ( _rdt = Services . GetService < IRunningDocumentTable > ( ) ) ;
244
244
}
245
245
}
0 commit comments