[Python.NET] Python.Net for Python3: bug when converting a PyLong to a System.Int32
Serge WEINSTOCK
serge.weinstock at uk.bnpparibas.com
Fri Sep 26 17:52:40 CEST 2014
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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/pythondotnet/attachments/20140926/8d13eb89/attachment.html>
More information about the PythonDotNet
mailing list