StephanH
StephanH

Reputation: 470

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.

Upvotes: 2

Views: 6052

Answers (3)

glopes
glopes

Reputation: 4380

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

Upvotes: 1

Denise Skidmore
Denise Skidmore

Reputation: 2416

In my particular case (bitbucket unit testing), loading a newer runtime (.NET 7) by a linux distribution specific method worked. The dependency that would not load claimed to be .NET 6 compatible, but either it was lying or I was missing a deeper dependency of that runtime. Try uninstall/reinstall or upgrade of your runtime.

feeling stupid because I put the runtime in my trouble shooting document months ago and have been banging my head against the wall on it recently.

Upvotes: 0

LOST
LOST

Reputation: 3284

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+.

Upvotes: 1

Related Questions