private void CollectCandidates(ModuleInfo moduleInfo, string name, Dictionary <string, ImportInfo> importFullNameMap, CancellationToken cancellationToken) { if (!moduleInfo.CheckCircularImports()) { // bail out on circular imports return; } // add non module (imported) member AddNonImportedMemberWithName(moduleInfo, name, importFullNameMap); // add module (imported) members if it shows up in __all__ // // we are doing recursive dig down rather than just going through all modules loaded linearly // since path to how to get to a module is important. // for example, "join" is defined in "ntpath" or "macpath" and etc, but users are supposed to // use it through "os.path" which will automatically point to right module ex, "ntpath" based on // environment rather than "ntpath" directly. if we just go through module in flat list, then // we can miss "os.path" since it won't show in the module list. // for these modules that are supposed to be used with indirect path (imported name of the module), // we need to dig down to collect those with right path. foreach (var memberName in GetAllVariables(moduleInfo.Analysis)) { cancellationToken.ThrowIfCancellationRequested(); var pythonModule = moduleInfo.Module.GetMember(memberName) as IPythonModule; if (pythonModule == null) { continue; } var fullName = $"{moduleInfo.FullName}.{memberName}"; if (string.Equals(memberName, name)) { // nested module are all imported AddNameParts(fullName, moduleImported: true, memberImported: true, pythonModule, importFullNameMap); } // make sure we dig down modules only if we can use it from imports // for example, user can do "from numpy import char" to import char [defchararray] module // but user can not do "from numpy.char import x" since it is not one of known modules to us. // in contrast, users can do "from os import path" to import path [ntpath] module // but also can do "from os.path import x" since "os.path" is one of known moudles to us. var result = AstUtilities.FindImports( moduleInfo.CurrentFileAnalysis.Document.Interpreter.ModuleResolution.CurrentPathResolver, moduleInfo.CurrentFileAnalysis.Document.FilePath, GetRootNames(fullName), dotCount: 0, forceAbsolute: true); if (result is ImportNotFound) { continue; } moduleInfo.AddName(memberName); CollectCandidates(moduleInfo.With(pythonModule), name, importFullNameMap, cancellationToken); moduleInfo.PopName(); } // pop this module out so we can get to this module from // different path. // ex) A -> B -> [C] and A -> D -> [C] moduleInfo.ForgetModule(); }