Discussion:
[Python.NET] Python.Net for Python3: bug when converting a PyLong to a System.Int32
Serge WEINSTOCK
2014-09-26 15:52:40 UTC
Permalink
Hi Tony,

I've found a bug when trying to use Python integer as .Net int32. For example:
//=======================================================================
using System;
using Python.Runtime;

namespace TestPythonNet
{
public class ATest
{
public long a64;
public int a32;
public void f32(int a) { Console.WriteLine("got int {0}", a);}
public void f64(long a) { Console.WriteLine("got long {0}", a); }
}


class Program
{
static void Main(string[] args)
{
PythonEngine.PythonHome = @"D:\src\scratch\TestPythonNet\TestPythonNet\PythonRuntime";
PythonEngine.ProgramName = "PythonRuntime";
PythonEngine.Initialize();
PythonEngine.ImportModule("clr");
using (Py.GIL())
{
try
{
PythonEngine.RunSimpleString(
@"
import clr

clr.AddReference('TestPythonNet')
from TestPythonNet import ATest

f = ATest();
f.a64 = 10 # OK
f.a32 = 10 # Fails!
f.f64(-1) # OK
f.f32(-1) # Fails!

print('all fine!')
");

}
catch (PythonException e)
{
Console.WriteLine(e);
}
}
}
}
}
//=======================================================================
All the call from python using integer as .Net int will fail. This is due to the fact that python3 has only one type of integer: int64.

Furthermore, in the Python C API, all the conversion functions from or to int32 have disappeared.

I think that the following patch fixes the issue:
Src/runtime/converter.cs
//=======================================================================
static bool ToPrimitive(IntPtr value, Type obType, out Object result,
bool setError) {

IntPtr overflow = Exceptions.OverflowError;
TypeCode tc = Type.GetTypeCode(obType);
result = null;
IntPtr op;
int ival;

switch(tc) {

case TypeCode.String:
string st = Runtime.GetManagedString(value);
if (st == null) {
goto type_error;
}
result = st;
return true;

case TypeCode.Int32:
// Trickery to support 64-bit platforms.
if (IntPtr.Size == 4) {
//------ FIX START
// convert it to an python int64
op = Runtime.PyNumber_Long(value);

// if the conversion fails
if (op == IntPtr.Zero) {
if (Exceptions.ExceptionMatches(overflow)) {
goto overflow;
}
goto type_error;
}

// convert it to an int64
long lval = (long)Runtime.PyLong_AsLongLong(op);

// and try to convert it to an int32
if ((lval < int.MinValue) || (int.MaxValue < lval))
{
Runtime.Decref(op);
if (Exceptions.ExceptionMatches(overflow))
{
goto overflow;
}
goto type_error;
}
Runtime.Decref(op);
result = unchecked((int)lval);
return true;
//------ FIX END
}
else {
op = Runtime.PyNumber_Long(value)
//=======================================================================

I will send a pull request to the github repo . Could you have a look at it?

Thanks,
Serge


___________________________________________________________
This e-mail may contain confidential and/or privileged information. If you are not the intended recipient (or have received this e-mail in error) please notify the sender immediately and delete this e-mail. Any unauthorised copying, disclosure or distribution of the material in this e-mail is prohibited.

Please refer to http://www.bnpparibas.co.uk/en/email-disclaimer/ for additional disclosures.
Loading...