private static void GetPythonVersionFromPythonPath(string PythonPath, out int FoundMajorVersion, out int FoundMinorVersion, out int FoundBugfix)
        {
            SilentProcess.StdoutDataCapture dataCapture = new SilentProcess.StdoutDataCapture();
            SilentProcess process = SilentProcess.StartConsoleProcessSilently(PythonPath, "--version", dataCapture.DataReceivedHandler);

            process.WaitForExit();
            if (process.ExitCode == 0)
            {
                string versionString = dataCapture.GetData();
                string pattern       = @"Python (\d+)\.(\d+)\.(\d+)";
                Match  match         = Regex.Match(versionString, pattern);
                if (match.Success)
                {
                    FoundMajorVersion = Int32.Parse(match.Groups[1].Value);
                    FoundMinorVersion = Int32.Parse(match.Groups[2].Value);
                    FoundBugfix       = Int32.Parse(match.Groups[3].Value);
                }
                else
                {
                    throw new InvalidOperationException("Python version string did not match expected format");
                }
            }
            else
            {
                throw new InvalidOperationException(string.Format("Python.exe failed with status {0}", process.ExitCode));
            }
        }
        public static void InstallPythonPackage(string PythonPath, string PackagePath)
        {
            string packagePath = PackagePath;

            if (!File.Exists(packagePath))
            {
                packagePath = Path.Combine(Path.GetDirectoryName(WindowsHelpers.GetApplicationPath()), packagePath);
                if (!File.Exists(packagePath))
                {
                    throw new InvalidOperationException(string.Format("Python Package {0} not found", PackagePath));
                }
            }
            SilentProcess.StdoutDataCapture dataCapture = new SilentProcess.StdoutDataCapture();
            SilentProcess process = SilentProcess.StartConsoleProcessSilently(
                PythonPath,
                string.Format("-m pip install --no-index {0}", packagePath),
                dataCapture.DataReceivedHandler
                );

            process.WaitForExit();
            if (process.ExitCode != 0)
            {
                InstallLogger.Log(dataCapture.GetData());
                throw new PythonPackageInstallException(string.Format("Install of package {0} failed", PackagePath));
            }
        }
        private static string FindPythonUsingPyLauncher(string PyLauncherPath, int MajorVersion, int MinorVersion, bool Force32Bit)
        {
            string PyArgs;

            if (Force32Bit)
            {
                PyArgs = string.Format("-{0}.{1}-32 -c \"import sys; print(sys.executable)\"", MajorVersion, MinorVersion);
            }
            else
            {
                PyArgs = string.Format("-{0}.{1} -c \"import sys; print(sys.executable)\"", MajorVersion, MinorVersion);
            }
            SilentProcess.StdoutDataCapture dataCapture = new SilentProcess.StdoutDataCapture();
            SilentProcess process = SilentProcess.StartConsoleProcessSilently(PyLauncherPath, PyArgs, dataCapture.DataReceivedHandler);

            process.WaitForExit();
            if (process.ExitCode == 0)
            {
                return(dataCapture.GetData().Trim());
            }
            else
            {
                throw new InvalidOperationException(string.Format("Python.exe failed with status {0}", process.ExitCode));
            }
        }
        public static void GetPythonBitness(int MajorVersion, int MinorVersion, out bool Has32Bit, out bool Has64Bit)
        {
            Has64Bit = false;
            Has32Bit = false;
            string PythonPath = FindPython(MajorVersion, MinorVersion, false);
            string PyArgs     = "-c \"import platform; print(platform.architecture()[0])\"";

            SilentProcess.StdoutDataCapture dataCapture = new SilentProcess.StdoutDataCapture();
            SilentProcess process = SilentProcess.StartConsoleProcessSilently(PythonPath, PyArgs, dataCapture.DataReceivedHandler);

            process.WaitForExit();
            if (process.ExitCode == 0)
            {
                string bitnessString = dataCapture.GetData();
                string pattern       = @"(\d+)bit";
                Match  match         = Regex.Match(bitnessString, pattern);
                if (match.Success)
                {
                    if (match.Groups[1].Value == "64")
                    {
                        Has64Bit = true;
                    }
                    else if (match.Groups[1].Value == "32")
                    {
                        Has32Bit = true;
                    }
                }
            }
            if (Has64Bit && !Has32Bit)
            {
                PythonPath = null;
                try { PythonPath = FindPython(MajorVersion, MinorVersion, true); }
                catch { }
                if (PythonPath != null)
                {
                    dataCapture = new SilentProcess.StdoutDataCapture();
                    process     = SilentProcess.StartConsoleProcessSilently(PythonPath, PyArgs, dataCapture.DataReceivedHandler);
                    process.WaitForExit();
                    if (process.ExitCode == 0)
                    {
                        string bitnessString = dataCapture.GetData();
                        string pattern       = @"(\d+)bit";
                        Match  match         = Regex.Match(bitnessString, pattern);
                        if (match.Success)
                        {
                            if (match.Groups[1].Value == "64")
                            {
                                Has64Bit = true;
                            }
                            else if (match.Groups[1].Value == "32")
                            {
                                Has32Bit = true;
                            }
                        }
                    }
                }
            }
        }
        public static void UninstallPythonPackage(string PythonPath, string PackageName)
        {
            SilentProcess.StdoutDataCapture dataCapture = new SilentProcess.StdoutDataCapture();
            SilentProcess process = SilentProcess.StartConsoleProcessSilently(
                PythonPath,
                string.Format("-m pip uninstall -y {0}", PackageName),
                dataCapture.DataReceivedHandler
                );

            process.WaitForExit();
            if (process.ExitCode != 0)
            {
                InstallLogger.Log(dataCapture.GetData());
                throw new PythonPackageUninstallException(string.Format("Uninstall of package {0} failed", PackageName));
            }
        }
        public static List <PythonPackage> GetInstalledPythonPackages(string PythonPath)
        {
            List <PythonPackage> PythonPackages = new List <PythonPackage>();

            SilentProcess.StdoutDataCapture dataCapture = new SilentProcess.StdoutDataCapture();
            SilentProcess process = SilentProcess.StartConsoleProcessSilently(PythonPath, "-m pip list --format=\"json\" --no-index", dataCapture.DataReceivedHandler);

            process.WaitForExit();
            bool TryLegacy = true;

            if (process.ExitCode == 0)
            {
                try
                {
                    PythonPackages = ParseJsonPipList(SanitizePipOutput(dataCapture.GetData()));
                    TryLegacy      = false;
                }
                catch (Exception e)
                {
                    InstallLogger.Log("Error occurred while trying to parse pip JSON:");
                    InstallLogger.Log(e.ToString());
                    InstallLogger.Log("Falling back to legacy mode");
                }
            }
            if (TryLegacy)
            {
                //
                // Older versions of pip don't support the --format flag, parse the legacy format
                //
                dataCapture = new SilentProcess.StdoutDataCapture();
                process     = SilentProcess.StartConsoleProcessSilently(PythonPath, "-m pip list --no-index", dataCapture.DataReceivedHandler);
                process.WaitForExit();
                if (process.ExitCode == 0)
                {
                    PythonPackages = ParseLegacyPipList(SanitizePipOutput(dataCapture.GetData()));
                }
            }
            return(PythonPackages);
        }
        private static bool DetectPythonVersionUsingPyLauncher(string PyLauncherPath, int?MajorVersion, int?MinorVersion, bool Force32Bit, out int FoundMajorVersion, out int FoundMinorVersion, out int FoundBugfix)
        {
            int    foundMajorVersion;
            int    foundMinorVersion;
            int    foundBugFix;
            string PyArgs;

            //Try to find Python using the launcher
            if (MajorVersion == null && MinorVersion == null)
            {
                PyArgs = "--version";
            }
            else if (MajorVersion != null && MinorVersion == null)
            {
                PyArgs = string.Format("-{0} --version", MajorVersion.Value);
            }
            else if (MajorVersion != null && MinorVersion != null)
            {
                if (Force32Bit)
                {
                    PyArgs = string.Format("-{0}.{1}-32 --version", MajorVersion.Value, MinorVersion.Value);
                }
                else
                {
                    PyArgs = string.Format("-{0}.{1} --version", MajorVersion.Value, MinorVersion.Value);
                }
            }
            else
            {
                FoundMajorVersion = 0;
                FoundMinorVersion = 0;
                FoundBugfix       = 0;
                return(false);
            }
            SilentProcess.StdoutDataCapture dataCapture = new SilentProcess.StdoutDataCapture();
            SilentProcess process = SilentProcess.StartConsoleProcessSilently(PyLauncherPath, PyArgs, dataCapture.DataReceivedHandler);

            process.WaitForExit();
            if (process.ExitCode == 0)
            {
                string versionString = dataCapture.GetData();
                string pattern       = @"Python (\d+)\.(\d+)\.(\d+)";
                Match  match         = Regex.Match(versionString, pattern);
                if (match.Success)
                {
                    foundMajorVersion = Int32.Parse(match.Groups[1].Value);
                    foundMinorVersion = Int32.Parse(match.Groups[2].Value);
                    foundBugFix       = Int32.Parse(match.Groups[3].Value);
                    if (MajorVersion != null && MinorVersion != null)
                    {
                        if (MajorVersion.Value == foundMajorVersion && MinorVersion.Value == foundMinorVersion)
                        {
                            FoundMajorVersion = foundMajorVersion;
                            FoundMinorVersion = foundMinorVersion;
                            FoundBugfix       = foundBugFix;
                            return(true);
                        }
                        else
                        {
                            FoundMajorVersion = 0;
                            FoundMinorVersion = 0;
                            FoundBugfix       = 0;
                            return(false);
                        }
                    }
                    else if (MajorVersion != null && MinorVersion == null)
                    {
                        if (MajorVersion.Value == foundMajorVersion)
                        {
                            FoundMajorVersion = foundMajorVersion;
                            FoundMinorVersion = foundMinorVersion;
                            FoundBugfix       = foundBugFix;
                            return(true);
                        }
                        else
                        {
                            FoundMajorVersion = 0;
                            FoundMinorVersion = 0;
                            FoundBugfix       = 0;
                            return(false);
                        }
                    }
                    else
                    {
                        FoundMajorVersion = foundMajorVersion;
                        FoundMinorVersion = foundMinorVersion;
                        FoundBugfix       = foundBugFix;
                        return(true);
                    }
                }
                else
                {
                    //Regex didn't match... probably because an error message of some kind was returned
                    FoundMajorVersion = 0;
                    FoundMinorVersion = 0;
                    FoundBugfix       = 0;
                    return(false);
                }
            }
            //Process returned an error
            FoundMajorVersion = 0;
            FoundMinorVersion = 0;
            FoundBugfix       = 0;
            return(false);
        }