Exemple #1
0
 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;
 }
Exemple #10
0
 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);
        }
Exemple #12
0
        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());
        }
Exemple #14
0
        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
                       ));
        }