4

I'm doing a project that uses python as background script and C# as GUI. My problem is that I can't figure out how to cause my GUI to automatically search for the pythonw.exe file in order to run my python scripts.

Currently I'm using this path:

ProcessStartInfo pythonInfo = new ProcessStartInfo(@"C:\\Users\\Omri\\AppData\\Local\\Programs\\Python\\Python35-32\\pythonw.exe");

but I want it to auto detect the path of pythonw.exe (I need to submit the project and it won't run on others computers unless they change the code itself)

Any suggestions may be helpful.

7 Answers 7

11

Inspired by @Shashi Bhushan's answer I made this function for getting the Python path reliably;

using Microsoft.Win32;
private static string GetPythonPath(string requiredVersion = "", string maxVersion = "")
{
    string[] possiblePythonLocations = new string[3] {
        @"HKLM\SOFTWARE\Python\PythonCore\",
        @"HKCU\SOFTWARE\Python\PythonCore\",
        @"HKLM\SOFTWARE\Wow6432Node\Python\PythonCore\"
    };

    //Version number, install path
    Dictionary<string, string> pythonLocations = new Dictionary<string, string>();

    foreach (string possibleLocation in possiblePythonLocations)
    {
        string regKey = possibleLocation.Substring(0, 4),
               actualPath = possibleLocation.Substring(5);
        RegistryKey theKey = regKey == "HKLM" ? Registry.LocalMachine : Registry.CurrentUser;
        RegistryKey theValue = theKey.OpenSubKey(actualPath);

        foreach (var v in theValue.GetSubKeyNames())
            if (theValue.OpenSubKey(v) is RegistryKey productKey)
                try
                {
                    string pythonExePath = productKey.OpenSubKey("InstallPath").GetValue("ExecutablePath").ToString();
                            
                    // Comment this in to get (Default) value instead
                    // string pythonExePath = productKey.OpenSubKey("InstallPath").GetValue("").ToString();
                            
                    if (pythonExePath != null && pythonExePath != "")
                    {
                        //Console.WriteLine("Got python version; " + v + " at path; " + pythonExePath);
                        pythonLocations.Add(v.ToString(), pythonExePath);
                    }
                }
                catch
                {
                    //Install path doesn't exist
                }
    }

    if (pythonLocations.Count > 0)
    {
        System.Version desiredVersion = new(requiredVersion == "" ? "0.0.1" : requiredVersion);
        System.Version maxPVersion = new(maxVersion == "" ? "999.999.999" : maxVersion);

        string highestVersion = "", highestVersionPath = "";

        foreach (KeyValuePair<string, string> pVersion in pythonLocations)
        {
            //TODO; if on 64-bit machine, prefer the 64 bit version over 32 and vice versa
            int index = pVersion.Key.IndexOf("-"); //For x-32 and x-64 in version numbers
            string formattedVersion = index > 0 ? pVersion.Key.Substring(0, index) : pVersion.Key;

            System.Version thisVersion = new System.Version(formattedVersion);
            int comparison = desiredVersion.CompareTo(thisVersion),
                maxComparison = maxPVersion.CompareTo(thisVersion);

            if (comparison <= 0)
            {
                //Version is greater or equal
                if (maxComparison >= 0)
                {
                    desiredVersion = thisVersion;

                    highestVersion = pVersion.Key;
                    highestVersionPath = pVersion.Value;
                }
                //else
                //    Console.WriteLine("Version is too high; " + maxComparison.ToString());
            }
            //else
            //    Console.WriteLine("Version (" + pVersion.Key + ") is not within the spectrum.");$
        }

        //Console.WriteLine(highestVersion);
        //Console.WriteLine(highestVersionPath);
        return highestVersionPath;
    }

    return "";
}
Sign up to request clarification or add additional context in comments.

2 Comments

FYI that code throws an exception for me "Microsoft.Win32.RegistryKey.OpenSubKey(...) returned null." at the line; string pythonExePath = productKey.OpenSubKey("InstallPath").GetValue("ExecutablePath").ToString();
Please check your code - in my case it throws "Object reference not set to an instance of an object." while executing theValue.GetSubKeyNames() in the foreach loop
5

You can find python installation path by lookup following keys on windows machine.

HKLM\SOFTWARE\Python\PythonCore\versionnumber\InstallPath

HKCU\SOFTWARE\Python\PythonCore\versionnumber\InstallPath

for win64 bit machine

HKLM\SOFTWARE\Wow6432Node\Python\PythonCore\versionnumber\InstallPath

You can refer this post for how to read registry using C#

How to read value of a registry key c#

1 Comment

This is a complete wrong answer: I have no mentioned registry keys or key doesn't contain executable path. I did a fresh Python install from python.org/downloads Check my answer for the correct detection
2

Find the environment variable name in Windows, for that assembly and use Environment.GetEnvironmentVariable(variableName)

Check out How to add to the pythonpath in windows 7?

4 Comments

How would I know?! It should be the same across all windows installations, if it is done with the same installer.
Apparently not? I've checked.
as far as i know- python is on path. cant understand what are u suggesting me. is there any explanation to var environment? var name?
And I can't understand your comment. You are asking how to get the python executable, without hardcoding it. What I am saying is - the path to that executable is usually stored in Windows as environmental variable. I've just given you the function which you can use to retrieve the value... but you have to look into your Windows ENV variables and see what the name for it is.
2

An example on how to search for Python within the PATH environment variable:

var entries = Environment.GetEnvironmentVariable("path").Split(';');
string python_location = null;

foreach (string entry in entries)
{
    if (entry.ToLower().Contains("python"))
    {
        var breadcrumbs = entry.Split('\\');
        foreach (string breadcrumb in breadcrumbs)
        {
            if (breadcrumb.ToLower().Contains("python"))
            {
                python_location += breadcrumb + '\\';
                break;
            }
            python_location += breadcrumb + '\\';
        }
        break;
    }
}

Comments

0

Just change the FileName to "python.exe" if you already set python env path

private void runPython(string cmd, string args)
    {
        ProcessStartInfo start = new ProcessStartInfo();
        start.FileName = "python.exe";
        start.Arguments = string.Format("{0} {1}", cmd, args);
        start.UseShellExecute = false;
        start.RedirectStandardOutput = true;
        using (Process process = Process.Start(start))
        {
            using (StreamReader reader = process.StandardOutput)
            {
                string result = reader.ReadToEnd();
                Console.Write(result);
            }
        }
    }

Comments

0

On my machine, with Python 3.11 installed, I can query it by defining this property:

public string PythonInstallPath 
{ 
   get => (string)Microsoft.Win32.Registry.GetValue(
          @"HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\3.11\InstallPath",
          "ExecutablePath", null); 
}

Pythonw.exe is located in the same path, so you can do:

public string PythonWInstallPath 
{ 
   get => System.IO.Path.Combine(System.IO.Path.GetDirectoryName(PythonInstallPath), 
                                 "pythonw.exe"); 
}

There is also a way to look it up in the environment, check this out as an alternative.

Comments

0

Use this snippet:

public string FindPythonPath()
{
    using (var hiveKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default))
    using (var subkey = hiveKey?.OpenSubKey(@"SOFTWARE\Python\PythonCore"))
    {
        var subkeys = subkey?.GetSubKeyNames();
        if (subkeys.Length == 0) return string.Empty;

        var key = hiveKey.OpenSubKey(@"SOFTWARE\Python\PythonCore\"+subkeys.Last());
        key = key.OpenSubKey("InstallPath");
        return Path.GetDirectoryName((string) key.GetValue("ExecutablePath", string.Empty));
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.