Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pythonnet load clr-module - can add reference but cannot load namespace module

I am trying to load dlls into my python code. First of all, I installed the python package pythonnet

py -3.8 -m pip install pythonnet

I succeeded in using System.Array within my python code:

import sys
import clr, System
from System import Array, Int32
arr = clr.System.Array.CreateInstance(clr.System.Double,3,2)

However, I am not able to use my own custom DLLs. My C# library looks like:

using System;
namespace CsLibrary
{

    public class PyWrapper 
    {
        public PyWrapper() { }
        public void sayHello() { Console.WriteLine("Hello World"); }
    }
}

I can add the reference

from System.Reflection import Assembly

sys.path.append(r'<path>')
test = Assembly.GetReferencedAssemblies(clr.AddReference(r'CsLibrary'))
print('Dependencies:')
[print(i) for i in test]
print('\nLoaded:')
[print(i) for i in clr.ListAssemblies(False)]

The resulting output is:

    **Dependencies:**
    System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
    System.Console, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a


    **Loaded:**
    mscorlib
    clrmodule
    Python.Runtime
    System.Core
    System.Configuration
    System.Xml
    System
    __CodeGenerator_Assembly
    e__NativeCall_Assembly
    CsLibrary (Version=1.0.0.0, Culture=neutral, PublicKeyToken=null)

However, if I try to load the namespace as a module I receive the error: ModuleNotFoundError: No module named 'CsLibrary'

from CsLibrary import PyWrapper
wrapper = PyWrapper()
wrapper.sayHello()

I thought maybe its because of the missing dependencies. So, I put the System.Runtime.dll and System.Console.dll into the folder of the CyLibrary.dll and I forced the loading via code:

dll1 = Assembly.LoadFile(r'<path>\bin\System.Console.dll')
dll2 = Assembly.LoadFile(r'<path>\bin\System.Runtime.dll')

I successfully added the loaded DLLs, however, the results stayed the same. I have tried Python 3.6, 3.8 and 3.9. The C# library I created in release and debug for .NET 5.0, 6.0, 2.1 and 3.1 on two different machines each with the same result: "Computer says no." I don't know what else to try.

Do I need to do anything with the .deps.json or .pdb created during the build? Is the PublicKeyToken=null something I should be concerned about?

Provided I am successful at some point, can I assume that the code executed through the C# library will be faster than the same code in Python (if sufficiently complex)?

You can find some forum entries about the same issue and some people argue that no config.json was used. The usage of config.json is nowhere documented. However, you can find the same code snippet: Pythonnet dotnet core 'No module named'

from clr_loader import get_coreclr
from pythonnet import set_runtime # no module named pythonnet (requires pythonnet >=v3)

rt = get_coreclr("<path>config.json")
set_runtime(rt) # cannot be called unless pythonnet >=v3.0 is install

My config file would look like (but I don't use it yet):

{
  "runtimeOptions": {
    "tfm": "netcoreapp3.1",
    "framework": {
      "name": "Microsoft.NETCore.App",
      "version": "3.1.0"
    },
    "configProperties": {
      "System.Reflection.Metadata.MetadataUpdater.IsSupported": false
    }
  }
}

Thank you in advance.

Edit: I updated pythonnet to version 3.0.2b pre-release. This gave me access to an actual pythonnet import (set_runtime). To create the config file add

<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>

to the properties in the csproj. file within visual studio. This will create the config.json for you.

like image 972
StephanH Avatar asked Apr 21 '26 19:04

StephanH


2 Answers

For others who may have landed here in search of a similar answer: in my case the issue seems to be that Python.NET sometimes requires you to import the module immediately after the clr.AddReference command.

For example the below did not work for me:

import clr
clr.AddReference("Assembly1")
clr.AddReference("Assembly2")
from Assembly1 import MyType
from Assembly2 import AnotherType

But the following modification did:

import clr
clr.AddReference("Assembly1")
from Assembly1 import MyType
clr.AddReference("Assembly2")
from Assembly2 import AnotherType
like image 163
glopes Avatar answered Apr 24 '26 07:04

glopes


import clr without any configuration loads .NET Framework, and your DLL seems to be targeting .NET (Core) 5.

Also, pythonnet 2.x does not support .NET Core and does not support .NET 5+.

like image 24
LOST Avatar answered Apr 24 '26 09:04

LOST