@@ -114,6 +114,14 @@ private void TryReplaceMember(IVariable v, IPythonType sourceType, IPythonType s
114
114
MergeClass ( v , sourceClass , stubType , cancellationToken ) ;
115
115
break ;
116
116
117
+ case PythonFunctionType sourceFunction :
118
+ MergeMembers ( v , sourceFunction , stubType , cancellationToken ) ;
119
+ break ;
120
+
121
+ case PythonPropertyType sourceProperty :
122
+ MergeMembers ( v , sourceProperty , stubType , cancellationToken ) ;
123
+ break ;
124
+
117
125
case IPythonModule _:
118
126
// We do not re-declare modules.
119
127
break ;
@@ -146,7 +154,17 @@ private void MergeClass(IVariable v, IPythonClassType sourceClass, IPythonType s
146
154
// Replace the class entirely since stub members may use generic types
147
155
// and the class definition is important. We transfer missing members
148
156
// from the original class to the stub.
149
- _eval . DeclareVariable ( v . Name , v . Value , v . Source ) ;
157
+ //
158
+ // In case module is compiled, it is already a stub and has no locations
159
+ // for code navigation.. In this case we replace the entire variable by one
160
+ // from the stub rather than just the value since stub variable has location
161
+ // and its own root definition/reference chain.
162
+ if ( sourceType . DeclaringModule . ModuleType == ModuleType . Compiled ||
163
+ sourceType . DeclaringModule . ModuleType == ModuleType . CompiledBuiltin ) {
164
+ _eval . ReplaceVariable ( v ) ;
165
+ } else {
166
+ _eval . DeclareVariable ( v . Name , v . Value , v . Source ) ;
167
+ }
150
168
151
169
// First pass: go through source class members and pick those
152
170
// that are not present in the stub class.
@@ -158,7 +176,7 @@ private void MergeClass(IVariable v, IPythonClassType sourceClass, IPythonType s
158
176
continue ; // Do not add unknowns to the stub.
159
177
}
160
178
var sourceMemberType = sourceMember ? . GetPythonType ( ) ;
161
- if ( sourceMemberType is IPythonClassMember cm && cm . DeclaringType != sourceClass ) {
179
+ if ( sourceMemberType is IPythonClassMember cm && ! cm . DeclaringModule . Equals ( sourceType . DeclaringModule ) ) {
162
180
continue ; // Only take members from this class and not from bases.
163
181
}
164
182
if ( ! IsFromThisModuleOrSubmodules ( sourceMemberType ) ) {
@@ -305,7 +323,13 @@ private bool IsFromThisModuleOrSubmodules(IPythonType type) {
305
323
var thisModule = _eval . Module ;
306
324
var typeModule = type . DeclaringModule ;
307
325
var typeMainModuleName = typeModule . Name . Split ( '.' ) . FirstOrDefault ( ) ;
308
- return typeModule . Equals ( thisModule ) || typeMainModuleName == thisModule . Name ;
326
+ if ( typeModule . Equals ( thisModule ) || typeMainModuleName == thisModule . Name ) {
327
+ return true ;
328
+ }
329
+ // Check if module is explicitly imported by the current one. For example, 'os'
330
+ // imports 'nt' and os.pyi specifies functions from 'nt' such as mkdir and so on.
331
+ var imported = thisModule . GlobalScope . Variables [ typeModule . Name ] ;
332
+ return imported ? . Value != null && imported . Source == VariableSource . Import ;
309
333
}
310
334
}
311
335
}
0 commit comments