henon / Python.Included

A Python.NET based framework enabling .NET libraries to call into Python packages without depending on a local Python installation.
MIT License
321 stars 52 forks source link

Pip not installing #55

Closed BeckerJason closed 1 year ago

BeckerJason commented 1 year ago

I had this working at some point. Was able to narrow down that the current code is not correctly installing. my python folder is missing modules.

await Python.Included.Installer.SetupPython(); PythonEngine.Initialize(); await Python.Included.Installer.TryInstallPip(); await Python.Included.Installer.PipInstallModule("mediapipe"); await Python.Included.Installer.PipInstallModule("numpy"); await Python.Included.Installer.PipInstallModule("opencv-python"); await Python.Included.Installer.PipInstallModule("socket"); dynamic sys = Py.Import("sys"); string pythonInstallDir = sys.exec_prefix.ToString(); Debug.Print("Python installation directory: " + pythonInstallDir);

This shows the expected files: image

When clearing the folder and running again this is what I get: image

You can see the Scripts folder is missing

Ideas @henon

BeckerJason commented 1 year ago

If i step thru the await Python.Included.Installer.PipInstallModule(..) parts slowly it will sometimes work. it almost makes me wonder if the await is not working as expected. Just a thought

henon commented 1 year ago

can you eliminate which package it is that is not installed correctly? or is it always something different? If the former, test only with the offending package. So your theory is that it is a timing issue. If so, try adding await Task.Delay(3000) between the installations. All in all, you can only narrow the problem down by doing repeated tests with different constellations. Single package installation, multiple with and without waiting etc. The more data you sample the more you can rule out different things and in the end you'll probably find the issue.

You can also try to disable the stdout and stderror redirection in PipInstallModule to see if that makes a difference.

henon commented 1 year ago

could it be that pip starts subprocesses in the background which are not awaited by the main process?

BeckerJason commented 1 year ago

could it be that pip starts subprocesses in the background which are not awaited by the main process?

Im thinking this might be the case. it seems PIP takes FOREVER to install

BeckerJason commented 1 year ago

When using: Python.Included.Installer.LogMessage += Console.WriteLine; I get: RunCommand: Error with command: 'cd C:\Users\Jason\AppData\Local\python-3.11.0-embed-amd64 && python.exe Lib\get-pip.py' Cannot mix synchronous and asynchronous operation on process stream.

henon commented 1 year ago

You are on to something here, obviously this change https://github.com/henon/Python.Included/commit/f66fe356387642fef114d5257035780c92efa876 which I added due to #44 causes this. One must not mix BeginOutputReadline() with ReadToEnd() according to https://stackoverflow.com/questions/11460606/i-am-trying-to-read-the-output-of-a-process-in-c-sharp-but-i-get-this-message-c

Can you try what happens when you uncomment these three lines in Installer.cs line 444:

                // The documentation for Process.StandardOutput says to read before you wait otherwise you can deadlock!
                string output = process.StandardOutput.ReadToEnd();
                Log(output);
henon commented 1 year ago

the snippet in https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why that suggests to call ReadToEnd() before calling WaitForExit() does not use BeginOutputReadLine() so you might also try to just uncomment these two lines in line 433

                process.BeginOutputReadLine();
                process.BeginErrorReadLine();
BeckerJason commented 1 year ago

That fixed it! Are you planning to make another NUGET with this change or is this a problem that is specific to my project?

BeckerJason commented 1 year ago

the snippet in https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why that suggests to call ReadToEnd() before calling WaitForExit() does not use BeginOutputReadLine() so you might also try to just uncomment these two lines in line 433

                process.BeginOutputReadLine();
                process.BeginErrorReadLine();

Wanted to clarify that this was the fix

henon commented 1 year ago

I will upload a new version on nuget shortly