@@ -149,6 +149,10 @@ private void TryReplaceMember(IVariable v, IPythonType sourceType, IPythonType s
149
149
MergeMembers ( v , sourceFunction , stubType , cancellationToken ) ;
150
150
break ;
151
151
152
+ case PythonPropertyType sourceProperty :
153
+ MergeMembers ( v , sourceProperty , stubType , cancellationToken ) ;
154
+ break ;
155
+
152
156
case IPythonModule _:
153
157
// We do not re-declare modules.
154
158
break ;
@@ -181,7 +185,17 @@ private void MergeMembers(IVariable v, IPythonType sourceType, IPythonType stubT
181
185
// Replace the class entirely since stub members may use generic types
182
186
// and the class definition is important. We transfer missing members
183
187
// from the original class to the stub.
184
- _eval . DeclareVariable ( v . Name , v . Value , v . Source ) ;
188
+ //
189
+ // In case module is compiled, it is already a stub and has no locations
190
+ // for code navigation.. In this case we replace the entire variable by one
191
+ // from the stub rather than just the value since stub variable has location
192
+ // and its own root definition/reference chain.
193
+ if ( sourceType . DeclaringModule . ModuleType == ModuleType . Compiled ||
194
+ sourceType . DeclaringModule . ModuleType == ModuleType . CompiledBuiltin ) {
195
+ _eval . ReplaceVariable ( v ) ;
196
+ } else {
197
+ _eval . DeclareVariable ( v . Name , v . Value , v . Source ) ;
198
+ }
185
199
186
200
// First pass: go through source class members and pick those
187
201
// that are not present in the stub class.
@@ -193,7 +207,7 @@ private void MergeMembers(IVariable v, IPythonType sourceType, IPythonType stubT
193
207
continue ; // Do not add unknowns to the stub.
194
208
}
195
209
var sourceMemberType = sourceMember ? . GetPythonType ( ) ;
196
- if ( sourceMemberType is IPythonClassMember cm && cm . DeclaringType != sourceType ) {
210
+ if ( sourceMemberType is IPythonClassMember cm && ! cm . DeclaringModule . Equals ( sourceType . DeclaringModule ) ) {
197
211
continue ; // Only take members from this class and not from bases.
198
212
}
199
213
if ( ! IsFromThisModuleOrSubmodules ( sourceMemberType ) ) {
@@ -340,7 +354,13 @@ private bool IsFromThisModuleOrSubmodules(IPythonType type) {
340
354
var thisModule = _eval . Module ;
341
355
var typeModule = type . DeclaringModule ;
342
356
var typeMainModuleName = typeModule . Name . Split ( '.' ) . FirstOrDefault ( ) ;
343
- return typeModule . Equals ( thisModule ) || typeMainModuleName == thisModule . Name ;
357
+ if ( typeModule . Equals ( thisModule ) || typeMainModuleName == thisModule . Name ) {
358
+ return true ;
359
+ }
360
+ // Check if module is explicitly imported by the current one. For example, 'os'
361
+ // imports 'nt' and os.pyi specifies functions from 'nt' such as mkdir and so on.
362
+ var imported = thisModule . GlobalScope . Variables [ typeModule . Name ] ;
363
+ return imported ? . Value != null && imported . Source == VariableSource . Import ;
344
364
}
345
365
}
346
366
}
0 commit comments