private InterpreterConfiguration(Dictionary <string, object> properties) { Id = Read(properties, nameof(Id)); _description = Read(properties, nameof(Description)) ?? ""; PrefixPath = Read(properties, nameof(PrefixPath)); InterpreterPath = Read(properties, nameof(InterpreterPath)); WindowsInterpreterPath = Read(properties, nameof(WindowsInterpreterPath)); PathEnvironmentVariable = Read(properties, nameof(PathEnvironmentVariable)); Architecture = InterpreterArchitecture.TryParse(Read(properties, nameof(Architecture))); try { Version = Version.Parse(Read(properties, nameof(Version))); } catch (ArgumentException) { Version = new Version(); } catch (FormatException) { Version = new Version(); } UIMode = 0; foreach (var bit in (Read(properties, nameof(UIMode)) ?? "").Split('|')) { InterpreterUIMode m; if (Enum.TryParse(bit, out m)) { UIMode |= m; } } }
private InterpreterConfiguration(Dictionary <string, object> properties) { Id = Read(properties, nameof(Id)); _description = Read(properties, nameof(Description)) ?? ""; InterpreterPath = Read(properties, nameof(InterpreterPath)); PathEnvironmentVariable = Read(properties, nameof(PathEnvironmentVariable)); LibraryPath = Read(properties, nameof(LibraryPath)); Architecture = InterpreterArchitecture.TryParse(Read(properties, nameof(Architecture))); try { Version = Version.Parse(Read(properties, nameof(Version))); } catch (Exception ex) when(ex is ArgumentException || ex is FormatException) { Version = new Version(); } if (properties.TryGetValue(nameof(SearchPaths), out object o)) { SearchPaths.Clear(); if (o is string s) { SearchPaths.AddRange(s.Split(';')); } else if (o is IEnumerable <string> ss) { SearchPaths.AddRange(ss); } } }
public void Search(RegistryKey root, InterpreterArchitecture assumedArch) { if (root == null) { return; } var companies = GetSubkeys(root); foreach (var company in companies) { if ("PyLauncher".Equals(company, StringComparison.OrdinalIgnoreCase)) { continue; } bool pythonCore = "PythonCore".Equals(company, StringComparison.OrdinalIgnoreCase); using (var companyKey = root.OpenSubKey(company)) { if (companyKey == null) { continue; } var companyDisplay = companyKey.GetValue("DisplayName") as string; var companySupportUrl = companyKey.GetValue("SupportUrl") as string; if (pythonCore) { companyDisplay = companyDisplay ?? PythonCoreCompanyDisplayName; companySupportUrl = companySupportUrl ?? PythonCoreSupportUrl; } else { companyDisplay = companyDisplay ?? company; } var tags = GetSubkeys(companyKey); foreach (var tag in tags) { using (var tagKey = companyKey.OpenSubKey(tag)) using (var installKey = tagKey?.OpenSubKey("InstallPath")) { var config = TryReadConfiguration(company, tag, tagKey, installKey, pythonCore, assumedArch); if (config == null) { continue; } if (_seenIds.Add(config.Id)) { var supportUrl = tagKey.GetValue("SupportUrl") as string ?? companySupportUrl; var info = new PythonInterpreterInformation(config, companyDisplay, companySupportUrl, supportUrl); _info.Add(info); } } } } } }
private static PythonInterpreterInformation CreateEnvironmentInfo(string prefixPath) { var name = Path.GetFileName(prefixPath); var description = name; var vendor = Strings.CondaEnvironmentDescription; var vendorUrl = string.Empty; var supportUrl = string.Empty; var interpreterPath = Path.Combine(prefixPath, CondaEnvironmentFactoryConstants.ConsoleExecutable); var windowsInterpreterPath = Path.Combine(prefixPath, CondaEnvironmentFactoryConstants.WindowsExecutable); InterpreterArchitecture arch = InterpreterArchitecture.Unknown; Version version = null; if (File.Exists(interpreterPath)) { using (var output = ProcessOutput.RunHiddenAndCapture( interpreterPath, "-c", "import sys; print('%s.%s' % (sys.version_info[0], sys.version_info[1]))" )) { output.Wait(); if (output.ExitCode == 0) { var versionName = output.StandardOutputLines.FirstOrDefault() ?? ""; if (!Version.TryParse(versionName, out version)) { version = null; } } } arch = CPythonInterpreterFactoryProvider.ArchitectureFromExe(interpreterPath); } else { return(null); } var config = new InterpreterConfiguration( CondaEnvironmentFactoryConstants.GetInterpreterId(CondaEnvironmentFactoryProvider.EnvironmentCompanyName, name), description, prefixPath, interpreterPath, windowsInterpreterPath, CondaEnvironmentFactoryConstants.PathEnvironmentVariableName, arch, version ); config.SwitchToFullDescription(); var unique = new PythonInterpreterInformation( config, vendor, vendorUrl, supportUrl ); return(unique); }
/// <summary> /// Reconstructs an interpreter configuration from a dictionary. /// </summary> public static VisualStudioInterpreterConfiguration CreateFromDictionary(Dictionary <string, object> properties) { var id = Read(properties, nameof(InterpreterConfiguration.Id)); var description = Read(properties, nameof(InterpreterConfiguration.Description)) ?? ""; var prefixPath = Read(properties, nameof(PrefixPath)); var interpreterPath = Read(properties, nameof(InterpreterConfiguration.InterpreterPath)); var windowsInterpreterPath = Read(properties, nameof(WindowsInterpreterPath)); var pathEnvironmentVariable = Read(properties, nameof(InterpreterConfiguration.PathEnvironmentVariable)); var architecture = InterpreterArchitecture.TryParse(Read(properties, nameof(InterpreterConfiguration.Architecture))); var version = default(Version); try { version = Version.Parse(Read(properties, nameof(Version))); } catch (Exception ex) when(ex is ArgumentException || ex is FormatException) { version = new Version(); } InterpreterUIMode uiMode = 0; foreach (var bit in (Read(properties, nameof(UIMode)) ?? "").Split('|')) { if (Enum.TryParse(bit, out InterpreterUIMode m)) { uiMode |= m; } } var configuration = new VisualStudioInterpreterConfiguration(id, description, prefixPath, interpreterPath, windowsInterpreterPath, pathEnvironmentVariable, architecture, version, uiMode); if (properties.TryGetValue(nameof(InterpreterConfiguration.SearchPaths), out object o)) { configuration.SearchPaths.Clear(); switch (o) { case string s: configuration.SearchPaths.AddRange(s.Split(';')); break; case IEnumerable <string> ss: configuration.SearchPaths.AddRange(ss); break; } } return(configuration); }
public VisualStudioInterpreterConfiguration( string id, string description, string prefixPath = null, string pythonExePath = null, string winPath = "", string pathVar = "", InterpreterArchitecture architecture = default(InterpreterArchitecture), Version version = null, InterpreterUIMode uiMode = InterpreterUIMode.Normal ) : base(id, description, pythonExePath, pathVar, string.Empty, string.Empty, architecture, version) { PrefixPath = prefixPath; WindowsInterpreterPath = string.IsNullOrEmpty(winPath) ? pythonExePath : winPath; UIMode = uiMode; }
/// <summary> /// Constructs a new interpreter configuration based on the provided values. /// </summary> public InterpreterConfiguration( string id, string description, string pythonExePath = null, string pathVar = "", string libPath = null, string sitePackagesPath = null, InterpreterArchitecture architecture = default(InterpreterArchitecture), Version version = null ) { Id = id; _description = description ?? string.Empty; InterpreterPath = pythonExePath; PathEnvironmentVariable = pathVar; Architecture = architecture ?? InterpreterArchitecture.Unknown; Version = version ?? new Version(); LibraryPath = libPath ?? string.Empty; SitePackagesPath = sitePackagesPath ?? string.Empty; }
public NotFoundInterpreterFactory( string id, Version version, string description = null, string prefixPath = null, InterpreterArchitecture architecture = default(InterpreterArchitecture), string descriptionSuffix = null) { Configuration = new VisualStudioInterpreterConfiguration( id, description ?? "Unknown Python {0}{1: ()} (unavailable)".FormatUI(version, architecture), prefixPath, null, null, null, architecture, version, InterpreterUIMode.CannotBeDefault | InterpreterUIMode.CannotBeConfigured ); }
/// <summary> /// <para>Constructs a new interpreter configuration based on the /// provided values.</para> /// <para>No validation is performed on the parameters.</para> /// <para>If winPath is null or empty, /// <see cref="WindowsInterpreterPath"/> will be set to path.</para> /// </summary> public InterpreterConfiguration( string id, string description, string prefixPath = null, string path = null, string winPath = "", string pathVar = "", InterpreterArchitecture arch = default(InterpreterArchitecture), Version version = null, InterpreterUIMode uiMode = InterpreterUIMode.Normal ) { Id = id; Description = description; PrefixPath = prefixPath; InterpreterPath = path; WindowsInterpreterPath = string.IsNullOrEmpty(winPath) ? path : winPath; PathEnvironmentVariable = pathVar; Architecture = arch ?? InterpreterArchitecture.Unknown; Version = version ?? new Version(); UIMode = uiMode; }
private InterpreterConfiguration(Dictionary <string, object> properties) { Id = Read(properties, nameof(Id)); _description = Read(properties, nameof(Description)) ?? ""; PrefixPath = Read(properties, nameof(PrefixPath)); InterpreterPath = Read(properties, nameof(InterpreterPath)); WindowsInterpreterPath = Read(properties, nameof(WindowsInterpreterPath)); PathEnvironmentVariable = Read(properties, nameof(PathEnvironmentVariable)); Architecture = InterpreterArchitecture.TryParse(Read(properties, nameof(Architecture))); try { Version = Version.Parse(Read(properties, nameof(Version))); } catch (ArgumentException) { Version = new Version(); } catch (FormatException) { Version = new Version(); } UIMode = 0; foreach (var bit in (Read(properties, nameof(UIMode)) ?? "").Split('|')) { InterpreterUIMode m; if (Enum.TryParse(bit, out m)) { UIMode |= m; } } if (properties.TryGetValue(nameof(SearchPaths), out object o)) { SearchPaths.Clear(); if (o is string s) { SearchPaths.AddRange(s.Split(';')); } else if (o is IEnumerable <string> ss) { SearchPaths.AddRange(ss); } } }
/// <summary> /// Call to find interpreters in the associated project. Separated from /// the constructor to allow exceptions to be handled without causing /// the project node to be invalid. /// </summary> private bool DiscoverInterpreters(ProjectInfo projectInfo) { // <Interpreter Include="InterpreterDirectory"> // <Id>factoryProviderId;interpreterFactoryId</Id> // <Version>...</Version> // <InterpreterPath>...</InterpreterPath> // <WindowsInterpreterPath>...</WindowsInterpreterPath> // <PathEnvironmentVariable>...</PathEnvironmentVariable> // <Description>...</Description> // </Interpreter> var projectHome = PathUtils.GetAbsoluteDirectoryPath( Path.GetDirectoryName(projectInfo.FullPath), projectInfo.GetPropertyValue("ProjectHome") ); var factories = new Dictionary <string, FactoryInfo>(); foreach (var item in projectInfo.GetInterpreters()) { // Errors in these options are fatal, so we set anyError and // continue with the next entry. var dir = GetValue(item, "EvaluatedInclude"); if (!PathUtils.IsValidPath(dir)) { Log("Interpreter has invalid path: {0}", dir ?? "(null)"); continue; } dir = PathUtils.GetAbsoluteDirectoryPath(projectHome, dir); var id = GetValue(item, MSBuildConstants.IdKey); if (string.IsNullOrEmpty(id)) { Log("Interpreter {0} has invalid value for '{1}': {2}", dir, MSBuildConstants.IdKey, id); continue; } if (factories.ContainsKey(id)) { Log("Interpreter {0} has a non-unique id: {1}", dir, id); continue; } var verStr = GetValue(item, MSBuildConstants.VersionKey); Version ver; if (string.IsNullOrEmpty(verStr) || !Version.TryParse(verStr, out ver)) { Log("Interpreter {0} has invalid value for '{1}': {2}", dir, MSBuildConstants.VersionKey, verStr); continue; } // The rest of the options are non-fatal. We create an instance // of NotFoundError with an amended description, which will // allow the user to remove the entry from the project file // later. bool hasError = false; var description = GetValue(item, MSBuildConstants.DescriptionKey); if (string.IsNullOrEmpty(description)) { description = PathUtils.CreateFriendlyDirectoryPath(projectHome, dir); } var path = GetValue(item, MSBuildConstants.InterpreterPathKey); if (!PathUtils.IsValidPath(path)) { Log("Interpreter {0} has invalid value for '{1}': {2}", dir, MSBuildConstants.InterpreterPathKey, path); hasError = true; } else if (!hasError) { path = PathUtils.GetAbsoluteFilePath(dir, path); } var winPath = GetValue(item, MSBuildConstants.WindowsPathKey); if (!PathUtils.IsValidPath(winPath)) { Log("Interpreter {0} has invalid value for '{1}': {2}", dir, MSBuildConstants.WindowsPathKey, winPath); hasError = true; } else if (!hasError) { winPath = PathUtils.GetAbsoluteFilePath(dir, winPath); } var pathVar = GetValue(item, MSBuildConstants.PathEnvVarKey); if (string.IsNullOrEmpty(pathVar)) { pathVar = "PYTHONPATH"; } var arch = InterpreterArchitecture.TryParse(GetValue(item, MSBuildConstants.ArchitectureKey)); string fullId = GetInterpreterId(projectInfo.FullPath, id); FactoryInfo info; if (hasError) { info = new ErrorFactoryInfo(fullId, ver, description, dir); } else { info = new ConfiguredFactoryInfo(this, new InterpreterConfiguration( fullId, description, dir, path, winPath, pathVar, arch, ver, InterpreterUIMode.CannotBeDefault | InterpreterUIMode.CannotBeConfigured | InterpreterUIMode.SupportsDatabase )); } MergeFactory(projectInfo, factories, info); } HashSet <FactoryInfo> previousFactories = new HashSet <FactoryInfo>(); if (projectInfo.Factories != null) { previousFactories.UnionWith(projectInfo.Factories.Values); } HashSet <FactoryInfo> newFactories = new HashSet <FactoryInfo>(factories.Values); bool anyChange = !newFactories.SetEquals(previousFactories); if (anyChange || projectInfo.Factories == null) { // Lock here mainly to ensure that any searches complete before // we trigger the changed event. lock (projectInfo) { projectInfo.Factories = factories; } foreach (var removed in previousFactories.Except(newFactories)) { projectInfo.ContextProvider.InterpreterUnloaded( projectInfo.Context, removed.Config ); IDisposable disp = removed as IDisposable; if (disp != null) { disp.Dispose(); } } foreach (var added in newFactories.Except(previousFactories)) { foreach (var factory in factories) { projectInfo.ContextProvider.InterpreterLoaded( projectInfo.Context, factory.Value.Config ); } } } return(anyChange); }
private InterpreterConfiguration TryReadConfiguration( string company, string tag, RegistryKey tagKey, RegistryKey installKey, bool pythonCoreCompatibility, InterpreterArchitecture assumedArch ) { if (tagKey == null || installKey == null) { return(null); } var prefixPath = installKey.GetValue(null) as string; var exePath = installKey.GetValue("ExecutablePath") as string; var exewPath = installKey.GetValue("WindowedExecutablePath") as string; if (pythonCoreCompatibility && !string.IsNullOrEmpty(prefixPath)) { if (string.IsNullOrEmpty(exePath)) { exePath = PathUtils.GetAbsoluteFilePath(prefixPath, CPythonInterpreterFactoryConstants.ConsoleExecutable); } if (string.IsNullOrEmpty(exewPath)) { exewPath = PathUtils.GetAbsoluteFilePath(prefixPath, CPythonInterpreterFactoryConstants.WindowsExecutable); } } var version = tagKey.GetValue("Version") as string; if (pythonCoreCompatibility && string.IsNullOrEmpty(version) && tag.Length >= 3) { version = tag.Substring(0, 3); } Version sysVersion; var sysVersionString = tagKey.GetValue("SysVersion") as string; if (pythonCoreCompatibility && string.IsNullOrEmpty(sysVersionString) && tag.Length >= 3) { sysVersionString = tag.Substring(0, 3); } if (string.IsNullOrEmpty(sysVersionString) || !Version.TryParse(sysVersionString, out sysVersion)) { sysVersion = new Version(0, 0); } PythonLanguageVersion langVersion; try { langVersion = sysVersion.ToLanguageVersion(); } catch (InvalidOperationException) { langVersion = PythonLanguageVersion.None; sysVersion = new Version(0, 0); } InterpreterArchitecture arch; if (!InterpreterArchitecture.TryParse(tagKey.GetValue("SysArchitecture", null) as string, out arch)) { arch = assumedArch; } if (arch == InterpreterArchitecture.Unknown && File.Exists(exePath)) { switch (NativeMethods.GetBinaryType(exePath)) { case System.Reflection.ProcessorArchitecture.X86: arch = InterpreterArchitecture.x86; break; case System.Reflection.ProcessorArchitecture.Amd64: arch = InterpreterArchitecture.x64; break; } } if (pythonCoreCompatibility && sysVersion != null && sysVersion < new Version(3, 5) && arch == InterpreterArchitecture.x86) { // Older versions of CPython did not include // "-32" in their Tag, so we will add it here // for uniqueness. tag += "-32"; } var id = CPythonInterpreterFactoryConstants.GetInterpreterId(company, tag); var description = tagKey.GetValue("DisplayName") as string; if (string.IsNullOrEmpty(description)) { if (pythonCoreCompatibility) { description = "Python {0}{1: ()}".FormatUI(version, arch); } else { description = "{0} {1}".FormatUI(company, tag); } } return(new InterpreterConfiguration( id, description, prefixPath, exePath, exewPath, CPythonInterpreterFactoryConstants.PathEnvironmentVariableName, arch, sysVersion )); }
public void Search(RegistryKey root, InterpreterArchitecture assumedArch) { if (root == null) { return; } var companies = GetSubkeys(root); foreach (var company in companies) { if ("PyLauncher".Equals(company, StringComparison.OrdinalIgnoreCase)) { continue; } bool pythonCore = PythonCoreCompany.Equals(company, StringComparison.OrdinalIgnoreCase); using (var companyKey = root.OpenSubKey(company)) { if (companyKey == null) { continue; } var companyDisplay = companyKey.GetValue("DisplayName") as string; var companySupportUrl = companyKey.GetValue("SupportUrl") as string; if (pythonCore) { companyDisplay = companyDisplay ?? PythonCoreCompanyDisplayName; companySupportUrl = companySupportUrl ?? PythonCoreSupportUrl; } else { companyDisplay = companyDisplay ?? company; } var tags = GetSubkeys(companyKey); foreach (var tag in tags) { using (var tagKey = companyKey.OpenSubKey(tag)) using (var installKey = tagKey?.OpenSubKey("InstallPath")) { var config = TryReadConfiguration(company, tag, tagKey, installKey, pythonCore, assumedArch); if (config == null) { continue; } if (_seenIds.Add(config.Id)) { var supportUrl = tagKey.GetValue("SupportUrl") as string ?? companySupportUrl; // We don't want to send people to http://python.org, even // if that's what is in the registry, so catch and fix it. if (!string.IsNullOrEmpty(supportUrl)) { var url = supportUrl.TrimEnd('/'); if (url.Equals("http://www.python.org", StringComparison.OrdinalIgnoreCase) || url.Equals("http://python.org", StringComparison.OrdinalIgnoreCase)) { supportUrl = PythonCoreSupportUrl; } } var info = new PythonInterpreterInformation(config, companyDisplay, companySupportUrl, supportUrl); _info.Add(info); } } } } } InterpreterConfiguration.DisambiguateDescriptions(_info.Select(i => i.Configuration).ToArray()); }
private VisualStudioInterpreterConfiguration TryReadConfiguration( string company, string tag, RegistryKey tagKey, RegistryKey installKey, bool pythonCoreCompatibility, InterpreterArchitecture assumedArch ) { if (tagKey == null || installKey == null) { return(null); } string prefixPath, exePath, exewPath; try { prefixPath = PathUtils.NormalizePath(installKey.GetValue(null) as string); exePath = PathUtils.NormalizePath(installKey.GetValue("ExecutablePath") as string); exewPath = PathUtils.NormalizePath(installKey.GetValue("WindowedExecutablePath") as string); } catch (ArgumentException ex) { Debug.Fail(ex.ToUnhandledExceptionMessage(GetType())); return(null); } if (pythonCoreCompatibility && !string.IsNullOrEmpty(prefixPath)) { if (string.IsNullOrEmpty(exePath)) { try { exePath = PathUtils.GetAbsoluteFilePath(prefixPath, CPythonInterpreterFactoryConstants.ConsoleExecutable); } catch (ArgumentException) { } } if (string.IsNullOrEmpty(exewPath)) { try { exewPath = PathUtils.GetAbsoluteFilePath(prefixPath, CPythonInterpreterFactoryConstants.WindowsExecutable); } catch (ArgumentException) { } } } var version = tagKey.GetValue("Version") as string; if (pythonCoreCompatibility && string.IsNullOrEmpty(version) && tag.Length >= 3) { version = tag.Substring(0, 3); } var sysVersionString = tagKey.GetValue("SysVersion") as string; if (pythonCoreCompatibility && string.IsNullOrEmpty(sysVersionString) && tag.Length >= 3) { sysVersionString = tag.Substring(0, 3); } if (string.IsNullOrEmpty(sysVersionString) || !Version.TryParse(sysVersionString, out var sysVersion)) { sysVersion = new Version(0, 0); } if (sysVersion < new Version(3, 0)) { return(null); // Python 2.x is no longer supported. } try { sysVersion.ToLanguageVersion(); } catch (InvalidOperationException) { sysVersion = new Version(0, 0); } if (!InterpreterArchitecture.TryParse(tagKey.GetValue("SysArchitecture", null) as string, out var arch)) { arch = assumedArch; } if (arch == InterpreterArchitecture.Unknown && File.Exists(exePath)) { switch (NativeMethods.GetBinaryType(exePath)) { case System.Reflection.ProcessorArchitecture.X86: arch = InterpreterArchitecture.x86; break; case System.Reflection.ProcessorArchitecture.Amd64: arch = InterpreterArchitecture.x64; break; } } if (pythonCoreCompatibility && sysVersion != null && sysVersion < new Version(3, 5) && arch == InterpreterArchitecture.x86) { // Older versions of CPython did not include // "-32" in their Tag, so we will add it here // for uniqueness. tag += "-32"; } var pathVar = tagKey.GetValue("PathEnvironmentVariable") as string ?? CPythonInterpreterFactoryConstants.PathEnvironmentVariableName; var id = CPythonInterpreterFactoryConstants.GetInterpreterId(company, tag); var description = tagKey.GetValue("DisplayName") as string; if (string.IsNullOrEmpty(description)) { description = pythonCoreCompatibility ? "Python {0}{1: ()}".FormatUI(version, arch) : "{0} {1}".FormatUI(company, tag); } return(new VisualStudioInterpreterConfiguration( id, description, prefixPath, exePath, exewPath, pathVar, arch, sysVersion )); }