Skip to content

Commit

Permalink
Merge pull request #778 from Uniplore-X/pr-master
Browse files Browse the repository at this point in the history
fix: Converting PyList to JArray (or PyDict to JObject) will cause exception when existing bool type in python
  • Loading branch information
skadefro authored Sep 15, 2023
2 parents 2ee8f1c + 0e58006 commit 8f2410a
Show file tree
Hide file tree
Showing 3 changed files with 287 additions and 118 deletions.
52 changes: 4 additions & 48 deletions OpenRPA.Script/Activities/InvokeCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -471,57 +471,13 @@ public void Execute(CodeActivityContext context, string code, string language, D
}
else if (a.Value.ArgumentType == typeof(object))
{
if (PyString.IsStringType(pyobj))
{
Arguments[a.Key].Set(context, pyobj.ToString());
}
else if (PyNumber.IsNumberType(pyobj) && ("True" == pyobj.ToString() || "False" == pyobj.ToString()))
{
Arguments[a.Key].Set(context, bool.Parse(pyobj.ToString()));
}
else if (PyInt.IsIntType(pyobj))
{
Arguments[a.Key].Set(context, int.Parse(pyobj.ToString()));
}
else if (PyFloat.IsFloatType(pyobj))
{
Arguments[a.Key].Set(context, float.Parse(pyobj.ToString()));
}
else if (PyDict.IsDictType(pyobj))
{
try
{
var obj = Newtonsoft.Json.JsonConvert.DeserializeObject(pyobj.ToString(), typeof(JObject));
Arguments[a.Key].Set(context, obj);
}
catch (Exception _ex)
{
Log.Information("Failed variable " + parameter.Key + " of type " + a.Value.ArgumentType.FullName + " " + _ex.Message);
}
}
else if (PyList.IsListType(pyobj))
try
{
try
{
var obj = Newtonsoft.Json.JsonConvert.DeserializeObject(pyobj.ToString(), typeof(JArray));
Arguments[a.Key].Set(context, obj);
}
catch (Exception _ex)
{
Log.Information("Failed variable " + parameter.Key + " of type " + a.Value.ArgumentType.FullName + " " + _ex.Message);
}
Arguments[a.Key].Set(context, ParseUtils.PyObjectToObjectForObjectArgument(pyobj));
}
else
catch (Exception _ex)
{
try
{
var obj = Newtonsoft.Json.JsonConvert.DeserializeObject(pyobj.ToString(), a.Value.ArgumentType);
Arguments[a.Key].Set(context, obj);
}
catch (Exception _ex)
{
Log.Information("Failed variable " + parameter.Key + " of type " + a.Value.ArgumentType.FullName + " " + _ex.Message);
}
Log.Information("Failed variable " + parameter.Key + " of type " + a.Value.ArgumentType.FullName + " " + _ex.Message);
}
}
else
Expand Down
282 changes: 282 additions & 0 deletions OpenRPA.Script/Activities/ParseUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
using Newtonsoft.Json.Linq;
using Python.Runtime;
using System;
using System.Collections.Generic;

using OpenRPA.Interfaces;

namespace OpenRPA.Script.Activities
{
public class ParseUtils
{
public static object PyObjectToObjectForObjectArgumentWithGIL(PyObject pyobj)
{
try
{
InvokeCode.InitPython();
using (Py.GIL())
{
return PyObjectToObjectForObjectArgument(pyobj);
}
}
catch (Exception ex)
{
Log.Warning(ex.ToString());
throw new Exception("Failed for 'PyObjectToObjectForObjectArgument': " + ex.ToString());
}
}

public static object PyObjectToObjectForObjectArgument(PyObject pyobj)
{
object obj;
if (pyobj.IsNone())
{
obj = null;
}
else if (PyString.IsStringType(pyobj))
{
obj = pyobj.ToString();
}
else if (PyNumber.IsNumberType(pyobj) && ("True" == pyobj.ToString() || "False" == pyobj.ToString()))
{
obj = bool.Parse(pyobj.ToString());
}
else if (PyInt.IsIntType(pyobj))
{
obj = int.Parse(pyobj.ToString());
}
else if (PyFloat.IsFloatType(pyobj))
{
obj = float.Parse(pyobj.ToString());
}
else if (PyDict.IsDictType(pyobj))
{
obj = PyDictToJObject(new PyDict(pyobj));
}
else if (PyList.IsListType(pyobj))
{
obj = PyListToJArray(new PyList(pyobj));
}
else
{
obj = Newtonsoft.Json.JsonConvert.DeserializeObject(pyobj.ToString(), typeof(object));
}

return obj;
}


public static JArray PyListToJArrayWithGIL(PyList list)
{
try
{
InvokeCode.InitPython();
using (Py.GIL())
{
return PyListToJArray(list);
}
}
catch (Exception ex)
{
Log.Warning(ex.ToString());
throw new Exception("Failed for 'PyListToJArray': " + ex.ToString());
}
}

/// <summary>
/// Convert PyList to JArray to solve the problem of `True` (or `False`) in python causing conversion failure
/// </summary>
/// <param name="list"></param>
/// <returns></returns>
public static JArray PyListToJArray(PyList list)
{
JArray jarr = new JArray();
foreach (PyObject pyobj in list)
{
JToken value;
if (pyobj.IsNone())
{
value = null;
}
else if (PyString.IsStringType(pyobj))
{
value = pyobj.ToString();
}
else if (PyNumber.IsNumberType(pyobj) && ("True" == pyobj.ToString() || "False" == pyobj.ToString()))
{
value = bool.Parse(pyobj.ToString());
}
else if (PyInt.IsIntType(pyobj))
{
value = int.Parse(pyobj.ToString());
}
else if (PyFloat.IsFloatType(pyobj))
{
value = float.Parse(pyobj.ToString());
}
else if (PyDict.IsDictType(pyobj))
{
value = PyDictToJObject(new PyDict(pyobj));
}
else if (PyList.IsListType(pyobj))
{
value = PyListToJArray(new PyList(pyobj));
}
else
{ // ? process other types
value = pyobj.ToString();
}

jarr.Add(value);
}

return jarr;
}

public static JObject PyDictToJObjectWithGIL(PyDict dict)
{
try
{
InvokeCode.InitPython();
using (Py.GIL())
{
return PyDictToJObject(dict);
}
}
catch (Exception ex)
{
Log.Warning(ex.ToString());
throw new Exception("Failed for 'PyDictToJObject': " + ex.ToString());
}
}


/// <summary>
/// Convert PyDict to JObject to solve the problem of `True` (or `False`) in python causing conversion failure
/// </summary>
/// <param name="dict"></param>
/// <returns></returns>
public static JObject PyDictToJObject(PyDict dict)
{
JObject jobj = new JObject();
foreach(var key in dict.Keys())
{
PyObject pyobj = dict.GetItem(key);
JToken value;
if (pyobj.IsNone())
{
value = null;
}
else if (PyString.IsStringType(pyobj))
{
value = pyobj.ToString();
}
else if (PyNumber.IsNumberType(pyobj) && ("True" == pyobj.ToString() || "False" == pyobj.ToString()))
{
value = bool.Parse(pyobj.ToString());
}
else if (PyInt.IsIntType(pyobj))
{
value = int.Parse(pyobj.ToString());
}
else if (PyFloat.IsFloatType(pyobj))
{
value = float.Parse(pyobj.ToString());
}
else if (PyDict.IsDictType(pyobj))
{
value = PyDictToJObject(new PyDict(pyobj));
}
else if (PyList.IsListType(pyobj))
{
value = PyListToJArray(new PyList(pyobj));
}
else
{ // ? process other types
value = pyobj.ToString();
}

jobj.Add(key.ToString(), value);
}

return jobj;
}

public static PyObject ToPyObjectWithGIL(object obj)
{
try
{
InvokeCode.InitPython();
using (Py.GIL())
{
return ToPyObject(obj);
}
}
catch (Exception ex)
{
Log.Warning(ex.ToString());
throw new Exception("Failed for 'ToPyObject': " + ex.ToString());
}
}

/// <summary>
/// Convert objects in c# to PyObject (such as list or dict) to facilitate data access in python
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static PyObject ToPyObject(object obj)
{
if (obj == null)
{
return Runtime.None;
}
else if (obj is JObject)
{
PyDict pyDict = new PyDict();
foreach (var item in (JObject)obj)
{
pyDict.SetItem(item.Key, ToPyObject(item.Value));
}
return pyDict;
}
else if (obj is JArray)
{
PyList pyList = new PyList();
foreach (var item in (JArray)obj)
{
pyList.Append(ToPyObject(item));
}
return pyList;
}
else if (obj is JValue)
{
object value = ((JValue)obj).Value;
return ToPyObject(value);
}
else if (ScriptActivities.IsDictionary(obj, typeof(string)))
{
IDictionary<string, object> dict = (IDictionary<string, object>)obj;
PyDict pyDict = new PyDict();
foreach (var item in dict)
{
pyDict.SetItem(item.Key, ToPyObject(item.Value));
}
return pyDict;
}
else if (ScriptActivities.IsList(obj, null))
{
IList<object> list = (IList<object>)obj;
PyList pyList = new PyList();
foreach (var item in list)
{
pyList.Append(ToPyObject(item));
}
return pyList;
}
else
{
return obj.ToPython();
}
}
}
}
Loading

0 comments on commit 8f2410a

Please sign in to comment.