Py.GIL() is giving error pythonnet embedded python in C# - c#

I have the following C# code:
static void Main()
{
string pythonpath1 = #"C:\Users\user\Documents\pynet_test\Python\Python37";
string pythonpath2 = #"C:\Users\user\Documents\pynet_test\Python\Python37\lib";
string envpythonhome = #"C:\Users\user\Documents\pynet_test\Python\Python37\python37.dll";
Environment.SetEnvironmentVariable("PYTHONNET_PYDLL", envpythonhome, EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("PATH", pythonpath1, EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("PYTHONHOME", pythonpath1, EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("PYTHONPATH", pythonpath2, EnvironmentVariableTarget.Process);
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.WriteLine(DateTime.Now);
}
The error I am getting is:
System.MissingMethodException
HResult=0x80131513
Message=Method not found: 'System.Reflection.Emit.AssemblyBuilder System.AppDomain.DefineDynamicAssembly(System.Reflection.AssemblyName, System.Reflection.Emit.AssemblyBuilderAccess)'.
Source=Python.Runtime
StackTrace:
at Python.Runtime.CodeGenerator..ctor()
at Python.Runtime.DelegateManager..ctor()
at Python.Runtime.PythonEngine.Initialize(IEnumerable`1 args, Boolean setSysArgv, Boolean initSigs)
at Python.Runtime.PythonEngine.Initialize(Boolean setSysArgv, Boolean initSigs)
at Python.Runtime.PythonEngine.Initialize()
at Python.Runtime.Py.GIL()
at WrapperPython.Program.Main() in C:\Users\user\Documents\pynet_test\pynet_test\Program.cs:line 50
The Python environment is in the Project folder and this is the following specifications:
python version used : 3.7 (x64)
pythonnet version: 2.5.2-cp37-cp37m-win_amd64
OS : Windows Server 2019
Reference has been made to the python.Runtime.dll under site-packaged. CSproj looks like following:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Reference Include="Python.Runtime">
<HintPath>..\Python\Python37\Lib\site-packages\Python.Runtime.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
I have tried everything provided online but can't seem to find the issue. I have a hunch it's based on the environment variables but not sure how to proceed.

okay so python.net installation is really not well documented and the folks maintaining the python.net repository don't really help a lot since it's not a "support forum".
I solved this issue by installing the python.runtime.AllPlatflorms nuget package and pointing the environment variables to the right python folders/ files.
This works with python3.8 as well.

Related

C# references to C++ CLR x32 and x64

I created a C++ project in Visual Studio Class library CLR (.NET Framework):
#pragma once
using namespace System;
#ifdef _M_X64
namespace MyDLL64 {
#else
namespace MyDLL32 {
#endif
public ref class MyClass
{
public: static String^ Foo(String^ arg)
{
String^ str = arg->ToUpper();
return str;
}
};
}
Then I compiled two libraries(x86 and x64).
Thereafter I add them to references in my C# project
and added their methods to the code:
String res = "";
if (IntPtr.Size == 8)
{
res = MyDLL64.MyClass.Foo("test string");
}
else
{
res = MyDLL32.MyClass.Foo("test string");
}
Console.WriteLine(res);
But I am getting this error:
System.BadImageFormatException: "Could not load file or assembly 'MyDLL64, Version=1.0.8197.24341, Culture=neutral, PublicKeyToken=null', or one of their dependencies. An attempt was made to load a program with an invalid format."(or MyDLL32... if arch is 64 bit).
By the way, this code starts correctly without exceptions:
String res = "";
if (IntPtr.Size == 8)
{
res = MyDLL64.MyClass.Foo("test string");
}
if (1 > 2)
{
res = MyDLL32.MyClass.Foo("test string");
}
Console.WriteLine(res);
So how properly add x32 and x64 C++CLR dlls to my Any CPU C# DLL?
So how properly add x32 and x64 C++CLR dlls to my Any CPU C# DLL?
You can't. AnyCPU just means that the self process can be executed either as a 32 or 64 bit one depending on the architecture but once a 64 bit process is spawned it cannot access 32 bit images and vice versa.
If your C# project references native images, then instead of building one AnyCPU image you must create two separate images just like in case of the C++ project.
Specify x86 and x84 targets for the solution. And then if your 32/64-bit C++ dlls are named differently, then you can edit your .csproj file like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='x86'">
<PlatformTarget>x86</PlatformTarget>
<DefineConstants>$(DefineConstants);X86</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(Platform)'=='x86'">
<Reference Include="MyDLL32"/>
</ItemGroup>
<PropertyGroup Condition="'$(Platform)'=='x64'">
<PlatformTarget>x64</PlatformTarget>
<DefineConstants>$(DefineConstants);X64</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(Platform)'=='x64'">
<Reference Include="MyDLL64"/>
</ItemGroup>
</Project>
And then the C# code can have similar #if directives than the C++ one:
String res = "";
#if X64
res = MyDLL64.MyClass.Foo("test string");
#else
res = MyDLL32.MyClass.Foo("test string");
#endif
Console.WriteLine(res);
But IMHO it would be nicer if the C++ images used the same namespaces so the C# code does not need the #if directives and the different images could be handled purely in the .csproj file (in which case you don't need the DefineConstants either).

error when call the unmanaged resouce functions from c#.net core dll into vb.netcore windows application

I got Issues when I call unmanaged resource functions from C#.net core DLL into VB.net core windows application. The program execution just stops suddenly when the function is hit.
Please below is my code
DLL Unmanaged function
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
namespace TestLibrary1
{
public class Class1
{
[UnmanagedCallersOnlyAttribute]
public static IntPtr AddNE(IntPtr a)
{
try
{
IntPtr add = a;
return add;
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
}
return (IntPtr)0;
}
}
}
VB.netcore windows code below to call dll
Imports System.Runtime.InteropServices
Imports Google.Apis.Calendar.v3.Data
Public Class Form1
Private Const DllName As String = "TestLibrary1NE.dll"
<DllImport(DllName)>
Private Shared Function AddNE(ByVal a As IntPtr) As IntPtr
End Function
Private Sub btnSend_Click(sender As Object, e As EventArgs) Handles btnSend.Click
Try
Dim ptrAddress As IntPtr = Marshal.StringToHGlobalAnsi(txtAddress.Text.Trim())
Dim ptrResponse As IntPtr = AddNE(ptrAddress)
Dim strResponse As String = Marshal.PtrToStringAnsi(ptrResponse)
MessageBox.Show(strResponse)
Catch ex As EntryPointNotFoundException
Console.WriteLine(e.ToString())
End Try
End
End Sub
End Class
When the function AddNE (from the C# DLL) above is hit it suddenly stops the execution from nowhere.
May I know what is the solution to fix this and how to find out the error?
It's not mentioned in the question but the code uses the DNNE package to create a native library that exports all marked functions with the attribute UnmanagedCallersOnly.
The DNNE package needs that 3 files be distributed together:
The managed assembly (TestLibrary1.dll);
The native assembly (TestLibrary1NE.dll);
And the TestLibrary1.runtimeconfig.json.
The catch is that both managed assembly (TestLibrary1.dll) and native assembly (TestLibrary1NE.dll) should be distributed together. And not only that but also the TestLibrary1.runtimeconfig.json. This is because the native assembly calls the managed assembly internally so all the files should be on the same path.
DNNE needs on Windows the --runtime flag or MSBuild RuntimeIdentifier property to be set as target win-x86 or win-x64, and both projects should be the same. Check the 3rd bullet here in the docs.
Also, the project that uses TestLibrary1.dll should reference the project. Something like the following:
<ItemGroup>
<ProjectReference Include="..\TestLibrary1\TestLibrary1.csproj" />
</ItemGroup>
The changes to the C# project configuration file (TestLibrary1.csproj) are commented on below. EnableDynamicLoading should be true to generate the TestLibrary1.runtimeconfig.json. And DNNE needs both PlatformTarget and RuntimeIdentifier to be defined as x64 and win-x64 respectively.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>c_sharp</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<!-- Include the line below to generate the runtimeconfig.json -->
<EnableDynamicLoading>true</EnableDynamicLoading>
<!-- DNNE package asks to include those 2 also -->
<PlatformTarget>x64</PlatformTarget>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DNNE" Version="1.0.32" />
</ItemGroup>
</Project>

IronPython: Error when launching .py script from c#

I'm running into a similar problem as this guy: IronPython : Microsoft.Scripting.SyntaxErrorException: 'unexpected token '=''
Unfortunately, there we no answers on that thread.
This is my code:
var engine = Python.CreateEngine();
var scope = engine.CreateScope();
try
{
engine.ExecuteFile(String.Concat(Directory.GetParent(Environment.CurrentDirectory).Parent.Parent.FullName, "\\Client.py"), scope);
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
And then here's the .py (that doesn't do anything yet, really):
#imports
import os
import tempfile
#Test
print("Here we go.")
The abomination to get the full path for my python file was an attempt to check if it got the path wrong or couldn't find the file, wasn't the case but I left it there. Debugger shows that the path is correct. However, it always fails on engine.ExecuteFile(...). and catches an exception that, according to the debugger is null. I got this error:
Microsoft.Scripting.SyntaxErrorException
and then goofed around with settings, changing Tools > Options > Debugging > General > "Enable just my Code" from checked to unchecked which lead to me not getting the SyntaxErrorException anymore but instead it's now this, but it still fails at the same line, with an exception that is still null:
IronPython.Runtime.Exceptions.ImportException in Microsoft.Dynamic.dll
At this point I don't know if I made a step in the right direction or went one back. Can anyone help with this?
EDIT: I need to correct this. There currently is an exception that states: "No module named os" instead of being just null which makes sense considering the exception type.
I moved the Lib folder to my project folder and had the search path extended by it like this:
String projectPath = Directory.GetParent(Environment.CurrentDirectory).Parent.Parent.FullName;
var engine = Python.CreateEngine();
var libs = new[]
{
String.Concat(projectPath, "\\Lib")
};
var pySP = engine.GetSearchPaths();
foreach (String resource in libs)
{
pySP.Add(resource);
}
following this thread: IronPython: No module named json.
Then I undid the changes I made to the debugging settings, and lastly added NuGet packages. Maybe there is now redundance with the added search path and the newly added packages but I am not willing to test my luck and undo any of the changes. Here is my .csproj file, for anyone who might need it when in the same position:
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="IronPython" Version="2.7.10" />
<PackageReference Include="IronPython.Interpreter" Version="2.7.4" />
<PackageReference Include="IronPython.StdLib" Version="2.7.10" />
</ItemGroup>
</Project>

Is there an easy way to add multiple projects to a solution?

In some solutions I use direct references to internal projects during development and switch to nuget references for release. However, adding 30+ projects to new solutions manually is a tedious task.
I was wondering whether there is a quicker way to do this. With projects it's pretty easy because you just copy/paste the xml but solution files are not that easy to edit but maybe there is some trick?
You can use the dotnet CLI.
For Linux:
dotnet sln MySolution.sln add **/*.csproj
For Windows PowerShell:
dotnet sln MySolution.sln add (Get-ChildItem -Recurse *.csproj)
I've done some reaserch on the visualstudio extensibility based on #JamesFaix link and I managed to put together this small piece of code:
using System;
using System.IO;
using System.Linq;
using EnvDTE;
using EnvDTE80;
class Program
{
static void Main(string[] args)
{
// VS2019
var dteType = Type.GetTypeFromProgID("VisualStudio.DTE.16.0", true);
var dte = (EnvDTE.DTE)System.Activator.CreateInstance(dteType);
var sln = (SolutionClass)dte.Solution;
// Solution to add projects to
sln.Open(#"C:\Projects\MyProject\MySolution.sln");
// Projects should be added to the "lib" solution-folder.
var lib = FindSolutionFolderOrCreate(sln, "lib");
// These projects should be added.
var projectPaths = new[]
{
#"C:\Projects\MyLibs\Lib1.csproj",
#"C:\Projects\MyLibs\Lib2.csproj"
};
foreach (var path in projectPaths)
{
var name = Path.GetFileNameWithoutExtension(path);
// If project not already in the solution-folder then add it.
if(!(lib.Parent.ProjectItems.Cast<ProjectItem>().Any(pi => pi.Name == name)))
{
lib.AddFromFile(path);
}
}
dte.Solution.Close(true);
}
private static SolutionFolder FindSolutionFolderOrCreate(SolutionClass sln, string folderName)
{
foreach (var x in sln.Projects)
{
if (x is Project p && p.Name.Equals(folderName, StringComparison.OrdinalIgnoreCase))
{
return (SolutionFolder)p.Object;
}
}
var proj = (sln as Solution2).AddSolutionFolder(folderName);
return (SolutionFolder)proj.Object;
}
}
*.csproj file of this utility:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<!--<TargetFramework>netcoreapp2.2</TargetFramework>-->
<TargetFramework>net47</TargetFramework>
<EnableUnmanagedDebugging>true</EnableUnmanagedDebugging>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>full</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<Reference Include="EnvDTE">
<HintPath>..\..\..\..\..\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\PublicAssemblies\envdte.dll</HintPath>
</Reference>
<Reference Include="EnvDTE80">
<HintPath>..\..\..\..\..\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\PublicAssemblies\envdte80.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
I'm using net47 here because netcoreapp doesn't allow you to debug COM objects which makes it really a painful experience.
You'll also need references to the two EnvDTE files.

FileNotFoundException: Could not load file or assembly 'System.Data.Entity'

I am trying to parse a dynamic Expression string using Linq
var x = Expression.Parameter(typeof(T), "x");
var e = Dynamic.DynamicExpression.ParseLambda(new[] { x }, null, "x.Id > 1");
var compiledDelegate = exp.Compile();
var values = new List<T>
{
new T
{
Id = 1
},
new T
{
Id = 2
}
};
var result = values.Where((Func<T, bool>)compiledDelegate);
When trying to execute the ParseLambda line, the code throws the below exception
I am using net standard 2.0 and Visual Studio 15.3.5.
I am pulling the below two packages with all the necessary ASP.NET core stuff.
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<NeutralLanguage>en</NeutralLanguage>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Linq.Dynamic" Version="1.0.7" />
<PackageReference Include="System.Linq.Expressions" Version="4.3.0" />
</ItemGroup>
<PropertyGroup>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>
With more googling I found that System.Data is not yet ported (if it will ever be) to .net standard 2.0 APIs so System.Linq.Dynamic was actually not fully compatible with .net standard 2.0.
Instead I found another port of the same assembly System.Linq.Dynamic.Core which did the job.

Categories