pythonnet Embedding Python in .net example failing to load module - c#

I'm trying to run the Embedding Python in .NET example from https://github.com/pythonnet/pythonnet. I've followed troubleshooting articles to set the proper %PYTHONPATH% and %PYTHONHOME% to my anaconda environment in the program base directory.
After activating my anaconda environment, I have successfully imported sys, and imp as a test, and also sucessfully used PythonEngine.RunSimpleString(), but the numpy example fails with Python.Runtime.PythonException: ImportError : No module named 'numpy'
importing numpy from python in this environment was successful, but this and other packages fail to import in pythonnet.
Pythonnet version: 2.3 x64 (installed using conda install -c pythonnet pythonnet)
Python version: Python 3.5 x64 (anaconda)
Operating System: Windows 10
The following code produces the error:
static void Main(string[] args)
{
string envPythonHome = AppDomain.CurrentDomain.BaseDirectory + "cntk-py35";
string envPythonLib = envPythonHome + #"\Lib";
Environment.SetEnvironmentVariable("PYTHONHOME", envPythonHome, EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("PATH", envPythonHome + ";" + Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine), EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("PYTHONPATH", envPythonLib, EnvironmentVariableTarget.Process);
PythonEngine.PythonHome = envPythonHome;
PythonEngine.PythonPath = Environment.GetEnvironmentVariable("PYTHONPATH");
using (Py.GIL())
{
dynamic np = Py.Import("numpy");
Console.WriteLine(np.cos(np.pi * 2));
dynamic sin = np.sin;
Console.WriteLine(sin(5));
double c = np.cos(5) + sin(5);
Console.WriteLine(c);
dynamic a = np.array(new List<float> { 1, 2, 3 });
Console.WriteLine(a.dtype);
dynamic b = np.array(new List<float> { 6, 5, 4 }, dtype: np.int32);
Console.WriteLine(b.dtype);
Console.WriteLine(a * b);
Console.ReadKey();
}
}
It seems that any package under site-packages in my environment similarly fail. Adding to %PATH% did not work. Is there a way to get pythonnet to recognize and load these modules?

Setting up your python environment in .NET is a bit cumbersome.This issue is not well detailed on pythonnet website or most of suggested solutions I have found on the internet did not work for my computer. The reason is that every computer may have a different python setup environment (depending how you have installed python and the libraries). It took me a while as well but finally I have succeeded to call python modules and .py scripts from .NET. Here is what I did.
Pythonnet version: 2.4.0 x64 (installed using pip install # Anaconda CMD prompt)
Python version: Python 3.7 x64 (Anaconda)
Operating System: Windows 10
Keep in mind that everyone has a different Python environment, that is why you have to configure your environment first (in your VS project).
First, we need to assign "PATH", "PYTHONHOME" and "PYTHONPATH" variables.
in C# use:
string pythonPath1 = #"C:\Users\<your username>\Anaconda3";
string pythonPath2 = #"C:\Users\<your username>\Anaconda3\lib\site-packages";
Environment.SetEnvironmentVariable("PATH", pythonPath1, EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("PYTHONHOME", pythonPath1, EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("PYTHONPATH", pythonPath2, EnvironmentVariableTarget.Process);
I have used Anaconda to install python runtime and packages. Note that default Anaconda installation is under C:\Users(your username assigned in your computer)\Anaconda3. (You can find yours using code by (How can I get the current user directory?). If you did not use Anaconda, you need to locate the directory where python packages are installed on your computer.
1-C:\Users\\Anaconda3 directory must have your version of python DLL (i.e.python37.dll).
2-C:\Users\\Anaconda3\lib\site-packages has the "modules" (i.e. python frameworks like 'numpy').
3-You must reference python runtime in your project (Python.Runtime.dll).(use Windows File Explorer to find the file. If you use Anaconda the runtime is under C:\Users\\Anaconda3 directory).
4-Add following on top of your code:
using Python.Runtime;
5-In VS Solution Explorer right click on your project and select 'Properties'
and make sure to set 'Platform Target' (either x64 or x86)
6-After doing all this, if you can NOT run some of the 'modules' and receive a "Can not load module" or "can not find module" exception message, then follow the instruction here (https://github.com/microsoft/vscode-python/issues/9218)
Usually, uninstalling/re-installing the module will resolve the issue by updating the version. (i.e. pip uninstall numpy/pip install numpy).
NOTE: The code still works, even if you do not set PYTHONPATH variable above. PYTHONPATH variable is used, when you need to call a custom .py script, where you identify the directory where your file resides. A descriptive example can be found at https://stackoverflow.com/a/57910578/7675537
UPDATE: I have realized that one easy way to configure your Python Environment is using Visual Studio (I use VS 2017 Community version). Just go to Python in Visual Studio and go through the example. In VS under 'Python Environments' you can observe all the setups you have in your computer. I had problems to run .py scripts, like not being able to use 'import matplotlib.pyplot' and spent several hours reading articles on the internet but could not find a solution. Finally I switched my environment to 'C:\Users\\AppData\Local\Programs\Python\Python37\' and installed all the missing packages from visual studio's list (of suggestions) and it worked. I think calling Anaconda environment from .NET (via pythonnet or else) has problems. I would suggest not to use your Anaconda python environment if you make .NET calls to python. I use:
private static string pythonPath1 = #"C:\Users\<your name>\AppData\Local\Programs\Python\Python37";
static void Main(string[] args)
{
Test();
}
private static void Test()
{
string pathToPython = pythonPath1;
string path = pathToPython + ";" +
Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine);
Environment.SetEnvironmentVariable("PATH", path, EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("PYTHONHOME", pathToPython, EnvironmentVariableTarget.Process);
var lib = new[]
{
#"C:\Users\<your name>\<your python code is here>",
Path.Combine(pathToPython, "Lib"),
Path.Combine(pathToPython, "DLLs")
};
string paths = string.Join("; ", lib);
Environment.SetEnvironmentVariable("PYTHONPATH", paths, EnvironmentVariableTarget.Process);
using (Py.GIL()) //Initialize the Python engine and acquire the interpreter lock
{
try
{
// import your script into the process
dynamic sampleModule = Py.Import("yourpythoncode");
}
catch (PythonException error)
{
Console.WriteLine("Error occured: ", error.Message);
}
}
}

I was able to import the modules by adding Lib/site-packages to the PYTHONPATH variable (rather than the PATH) which adds the folder to sys.path. It was necessary for any other python libraries and custom python code to add the corresponding folder to PYTHONPATH.

Related

How to install modules to IronPython in VisualStudio

I need to use Python code in the C# application. So I decide to install IronPython NuGet to my project in VisualStudio. When I try to run the script, I always have errors with the Python Modules (like numpy, json...).
I tried solutions like include path to the folder with modules.
# first try
var ipy = Python.CreateRuntime();
dynamic test = ipy.UseFile("some.py");
test.Test();
# error 1
IronPython.Runtime.Exceptions.ImportException: 'No module named numpy'
# the tried this
var engine = Python.CreateEngine();
var paths = engine.GetSearchPaths();
paths.Add(...pathToModules);
engine.SetSearchPaths(paths);
dynamic logging = engine.ImportModule("numpy");
#error 2
Microsoft.Scripting.SyntaxErrorException: 'unexpected token 'append''
I'm using Anaconda with Spyder, python version 3.5. The problem isn't about python version.
Can you help me please to solve it? It's possible to install some modules to the IronPython in VisualStudio environment?

Getting python script linked with C#

I am using Visual Studio 2017 with NuGet packages: IronPython installed.
I need to be able to get the python script working in the C# application without an end user having to install python. I can get basic applications to run without any problem by just IronPython, then I tested with the library I needed for the script to work and it no longer worked with just IronPython and it would then need to point at my python Lib folder in order to get the libraries it needs. Is there any way around this or is the end user going to have no choice but to install python and the library on their computer to get my application to work?
Code for reference:
using IronPython.Hosting;
namespace testApp {
class Program {
static void Main(string[] args) {
var py = Python.CreateEngine();
try {
py.ExecuteFile(#"python\test.py");
}
catch (Exception ex) {
Console.WriteLine(ex.Message + " - Error from visual studio");
}
Console.Read();
}
}
}
Python:
import sys
sys.path.append(r"C:\Users\Owner\AppData\Local\Programs\Python\Python36-32\Lib") # points to python interpreter
import os
from reportlab.pdfgen import canvas
c = canvas.Canvas("Test.pdf")
c.drawString(100, 100, "This is some test text!")
c.showPage()
c.save()

GhostscriptLibraryNotInstalledException running under 32-bit process requires native library

Using nuget in Visual Studio 2013, I installed Ghostscript.NET into my project on my Windows x64 PC.
Just to make sure I wasn't crazy, I checked it:
PM> Install-Package Ghostscript.NET
'Ghostscript.NET 1.2.0' already installed.
Project already has a reference to 'Ghostscript.NET 1.2.0'.
PM>
The project is used by multiple developers. It targets Any CPU, and needs to remain that way.
Here is my code:
public static void GhostscriptNetProcess(String fileName, String outputPath)
{
var version = GhostscriptVersionInfo.GetLastInstalledVersion();
var source = (fileName.IndexOf(' ') == -1) ? fileName : String.Format("\"{0}\"", fileName);
var output_file = (outputPath.IndexOf(' ') == -1) ? outputPath : String.Format("\"{0}\"", outputPath);
var gsArgs = new List<String>();
gsArgs.Add("-q");
gsArgs.Add("-dNOPAUSE");
gsArgs.Add("-dNOPROMPT");
gsArgs.Add("-sDEVICE=pdfwrite");
gsArgs.Add(String.Format(#"-sOutputFile={0}", output_file));
gsArgs.Add("-f");
gsArgs.Add(source);
var processor = new GhostscriptProcessor(version, false);
processor.Process(gsArgs.ToArray());
}
Whenever I attempt to debug the application, I get the following error message:
GhostscriptLibraryNotInstalledException was unhandled
An unhandled exception of type 'Ghostscript.NET.GhostscriptLibraryNotInstalledException' occurred in Ghostscript.NET.dll
Additional information: This managed library is running under 32-bit process and requires 32-bit Ghostscript native library installation on this machine! To download proper Ghostscript native library please visit: http://www.ghostscript.com/download/gsdnld.html
Looking up the Ghostscript.NET.GhostscriptLibraryNotInstalledException did not provide any useful information, though this post on CodeProject indicated that the debugger is running in 32-bit mode whereas I have the 64-bit version installed.
That's all well and good know, but how do I go about testing the new code I wrote that uses Ghostscript?
If you are testing with MS Test you have to set the processor architecture in which the tests are run, because Ghostscript.Net verifies the process architecture (Environment.Is64BitProcess) to search for the ghostscript installation in the registry.
In Menu > Test > Test Settings > Default Processor Architecture > X64.
Have you actually installed Ghostscript ?
Ghostscript.NET is merely a .NET interface to Ghostscript, it looks to me like the message:
"This managed library is running under 32-bit process and requires 32-bit Ghostscript native library installation on this machine! To download proper Ghostscript native library please visit: http://www.ghostscript.com/download/gsdnld.html"
is trying to tell you that you don;t have a 32-bit version of Ghostscript installed. It even tells you where to go to download a copy.
So have you installed Ghostscript ? Have you installed the 32-bit version of Ghostscript ?

Error when reading audio file?

I have the following function that I am attempting to use to determine the length of an MP3 file:
public static string GetMP3DurationBackup(string Filename)
{
string Duration = null;
WMPLib.WindowsMediaPlayer w = new WMPLib.WindowsMediaPlayer();
WMPLib.IWMPMedia m = w.newMedia(Filename);
if (m != null)
{
Duration = m.durationString;
}
w.close();
return Duration;
}
I have run into an issue where I get the following error:
Retrieving the COM class factory for component with CLSID
{6BF52A52-394A-11D3-B153-00C04F79FAA6} failed due to the following
error: 80040154..
when I call the above function from my web application (call below):
string test = MediaUtil.GetMP3DurationBackup(#"C:\Temp\Audio\bad.mp3");
But when I call it from a console application test harness I created (exact same call as above) it works fine. I have set the project that contains the function to target x86 in the Build properties, but that did not fix the issue.
Does anyone know why this would happen? Suggestions on where to start to debug this?
UPDATED FOR BOUNTY:
Ok, I've tried a number of things but I am still getting this error. Among other things I have tried the steps below which I felt were the most promising, but no dice:
Went into my registry and confirmed that the value at:
HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{6BF52A52-394A-11d3-B153-00C04F79FAA6}\InprocServer32
is refering to C:\WINDOWS\SysWOW64\wmp.dll
Opened command prompt,
navigated to C:\WINDOWS\SysWow64, ran: regsvr32.exe wmp.dll
I have created a console app test harness and I am able to reproduce the error if I run the test project in x64. If I switch it to x86 it works fine.
Does anyone have any idea of why the above would not resolve the issue? Suggestions on where to look next?
You say it doesn't work in x64, but you try to register the 32-bit version of wmp.dll (C:\Windows\SysWow64 contains 32-bit assemblies).
Try to register the x64 version of wmp.dll, which is located in C:\Windows\System32 on a 64-bit platform.
If you don't have this file then there probably is no 64bit Windows Media Player available for your platform. But there is a workaround:
Create a 32-bit console application that takes the mp3 filename as command line argument and outputs the duration to stdout using Console.WriteLine, then in the webapp, you call the console application and capture the output like in this example on MSDN
Give this lib a whirl. Its fast and has no special requirements for software to be installed on the machine.
http://naudio.codeplex.com/

"No module named fcntl" when py script run from c# but works from windows command line

I am calling a python script that uses imaplib.py and get the "no module named fcntl" error. From searching I found that this module is only available in unix and so I wonder if the py script is confused about what os it is running under. Again, script works fine under windows run directly from the python directory.
var engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
var ops = engine.Operations;
var script = engine.CreateScriptSourceFromFile("PyTest.py");
CompiledCode code = script.Compile();
//string scode = script.GetCode();
code.Execute(scope);
and the minimal py script to trigger it. Note that commenting out the import imaplib.py line will stop the error.
import sys
sys.path = ["Python\Lib"]
sys.platform = ["win32"]
import os
import os
import getopt
import getpass
import time
import imaplib
I traced it a bit to the subprocess.py that imaplib.py uses, there I noticed the sys.platform variable and tried setting it to win32 as above but made no difference. Something is different between the ironpython calling environment and the windows command prompt from the cpython folder.
First of all you're setting sys.platform to a list, it should be a string. .NET/CLI is a different platform than Win32 though, so just setting sys.platform won't help.
Some Googling suggests IronPython doesn't support the subprocess module (or the module doesn't support IronPython). There is a partial replacement here: http://www.ironpython.info/index.php?title=The_subprocess_module
There's also a bugreport with some discussion here: http://bugs.python.org/issue8110
The Microsoft distribution does not load the standard library by default.
You have to set the path in your code in order to access it.
The easiest way to do it is to create an environment variable called "IRONPYTHONPATH" which contains the path to the Lib folder of the IronPython installation.
Once you have created it, you can read the location as follows:
from System import Environment
pythonPath = Environment.GetEnvironmentVariable("IRONPYTHONPATH")
import sys
sys.path.append(pythonPath)
More details here.
http://www.ironpython.info/index.php/Using_the_Python_Standard_Library

Categories

Resources