Пример #1
0
        public static string GetUniqueId(string moduleName, string filePath, ModuleType moduleType, IServiceContainer services, AnalysisCachingLevel cachingLevel)
        {
            if (cachingLevel == AnalysisCachingLevel.None)
            {
                return(null);
            }
            if (moduleType == ModuleType.User)
            {
                // Only for tests.
                return($"{moduleName}");
            }

            var interpreter = services.GetService <IPythonInterpreter>();
            var fs          = services.GetService <IFileSystem>();

            var moduleResolution = interpreter.ModuleResolution;
            var modulePathType   = GetModulePathType(filePath, moduleResolution.LibraryPaths, fs);

            switch (modulePathType)
            {
            case PythonLibraryPathType.Site when cachingLevel < AnalysisCachingLevel.Library:
                return(null);

            case PythonLibraryPathType.StdLib when cachingLevel < AnalysisCachingLevel.System:
                return(null);
            }

            if (!string.IsNullOrEmpty(filePath) && modulePathType == PythonLibraryPathType.Site)
            {
                // Module can be a submodule of a versioned package. In this case we want to use
                // version of the enclosing package so we have to look up the chain of folders.
                var moduleRootName     = moduleName.Split('.')[0];
                var moduleFilesFolder  = Path.GetDirectoryName(filePath);
                var installationFolder = Path.GetDirectoryName(moduleFilesFolder);

                var versionFolder = installationFolder;
                while (!string.IsNullOrEmpty(versionFolder))
                {
                    // If module is in site-packages and is versioned, then unique id = name + version + interpreter version.
                    // Example: 'requests' and 'requests-2.21.0.dist-info'.
                    // TODO: for egg (https://github.com/microsoft/python-language-server/issues/196), consider *.egg-info
                    var folders = fs.GetFileSystemEntries(versionFolder, "*-*.dist-info", SearchOption.TopDirectoryOnly)
                                  .Select(Path.GetFileName)
                                  .Where(n => n.StartsWith(moduleRootName, StringComparison.OrdinalIgnoreCase)) // Module name can be capitalized differently.
                                  .ToArray();

                    if (folders.Length == 1)
                    {
                        var fileName = Path.GetFileNameWithoutExtension(folders[0]);
                        var dash     = fileName.IndexOf('-');
                        return($"{moduleName}({fileName.Substring(dash + 1)})");
                    }
                    // Move up if nothing is found.
                    versionFolder = Path.GetDirectoryName(versionFolder);
                }
            }

            var config = interpreter.Configuration;

            if (moduleType.IsCompiled() || string.IsNullOrEmpty(filePath) || modulePathType == PythonLibraryPathType.StdLib)
            {
                // If module is a standard library, unique id is its name + interpreter version.
                return($"{moduleName}({config.Version.Major}.{config.Version.Minor})");
            }

            var parent = moduleResolution.CurrentPathResolver.GetModuleParentFromModuleName(moduleName);
            var hash   = HashModuleFileSizes(parent);

            // If all else fails, hash modules file sizes.
            return($"{moduleName}.{(ulong)hash}");
        }