6

I'm using Python.NET to load a C# Assembly to call C# code from Python. This works pretty cleanly, however I am having an issue calling a method that looks like this:

A method within Our.Namespace.Proj.MyRepo:

OutputObject GetData(string user, int anID, int? anOptionalID= null)

I can call the method for the case where the optional third argument is present but can't figure out what to pass for the third argument to match the null case.

import clr
clr.AddReference("Our.Namespace.Proj")
import System
from Our.Namespace.Proj import MyRepo

_repo = MyRepo()

_repo.GetData('me', System.Int32(1), System.Int32(2))  # works!

_repo.GetData('me', System.Int32(1))  # fails! TypeError: No method matches given arguments

_repo.GetData('me', System.Int32(1), None)  # fails! TypeError: No method matches given arguments

The iPython Notebook indicates that the last argument should be of type:

System.Nullable`1[System.Int32]

Just not sure how to create an object that will match the Null case.

Any suggestions on how to create a C# recognized Null object? I assumed passing the native Python None would work, but it does not.

denfromufa
  • 5,610
  • 13
  • 81
  • 138
skulz00
  • 769
  • 8
  • 18
  • 2
    I don't know Python.NET, but it seems, when you pass None to it, it probably only searches methods with reference type parameters. You could at least try an overload without the last parameter (and possible another overload with the last parameter being `object` to allow passing None (if this works) that then calls the first method with the last argument `as int?`.) – IS4 Nov 07 '14 at 17:04
  • 1
    Ended up refactoring the C# side to have overloaded methods (one with and one without the third parameter). Python.NET handles this fine. The downside is I have to call one of two methods conditionally based on presence of the last parameter. I will try the suggestion of having the last parameter be `object` for a third overloaded case on the C# side to allow passing None. Thanks! – skulz00 Nov 07 '14 at 18:01

3 Answers3

4

[EDIT]

This has been merged to pythonnet:

https://github.com/pythonnet/pythonnet/pull/460


I ran into the same issue with nullable primitives -- it seems to me that Python.NET doesn't support these types. I got around the problem by adding the following code in Python.Runtime.Converter.ToManagedValue() (\src\runtime\converter.cs)

if( obType.IsGenericType && obType.GetGenericTypeDefinition() == typeof(Nullable<>) )
{
    if( value == Runtime.PyNone )
    {
        result = null;
        return true;
    }
    // Set type to underlying type
    obType = obType.GetGenericArguments()[0];
}

I placed this code right underneath

if (value == Runtime.PyNone && !obType.IsValueType) {
    result = null;
    return true;
}

https://github.com/pythonnet/pythonnet/blob/4df6105b98b302029e524c7ce36f7b3cb18f7040/src/runtime/converter.cs#L320

denfromufa
  • 5,610
  • 13
  • 81
  • 138
antchi
  • 189
  • 1
  • 5
  • Are you saying that you modified the Python.NET source code? – skulz00 Dec 05 '14 at 22:16
  • 1
    Yes, I'm referring to Python.NET source code in http://sourceforge.net/p/pythonnet/code/147/tree/trunk. – antchi Dec 08 '14 at 01:15
  • Got it. Thanks! I will summarize the issue and post to http://sourceforge.net/p/pythonnet/bugs/ so that it can be integrated into next version. – skulz00 Dec 08 '14 at 14:37
2

I have no way to test this, but try

_repo.GetData('me', System.Int32(1), System.Nullable[System.Int32]())

Since you're saying that the optional parameter is Nullable, you need to create a new Nullable object of type Int32, or new System.Nullable<int>() in C# code.

I would have assumed that the first failing example would work, given that this is how optional parameters work in C#; calling the function without specifying the parameter at all.

ToastyMallows
  • 4,203
  • 5
  • 43
  • 52
  • Thanks for the suggestion. When I try to create `System.Nullable[System.Int32]()`, even outside of the call to GetData, I get a `TypeError: no constructor matches given arguments`. I also tried just passing in `System.Nullable[System.Int32]` and that gives me `ArgumentException: Object of type 'System.RuntimeType' cannot be converted to type 'System.Nullable\`1[System.Int32]'.` – skulz00 Nov 05 '14 at 14:16
  • Strange. I'm not familiar with that Python syntax, not sure what that `'1` is doing there. Hopefully someone smarter than me can crack this nut. I originally thought that you were using IronPython, you might wanna try that because it seems to handle optional parameters better. – ToastyMallows Nov 05 '14 at 14:34
  • That's not Python syntax, that's .NET syntax for generic types - `1 means 1 type parameter. – IS4 Nov 07 '14 at 16:58
  • I see. Not sure why Python.NET is chocking then. – ToastyMallows Nov 07 '14 at 18:22
1

You have to pass argument to generic function System.Nullable[System.Int32](0)

Pavel Sokolov
  • 104
  • 1
  • 6