Repository navigation
Expand file tree
/
Copy pathPyObjectSerializer.cs
More file actions
68 lines (57 loc) · 2.18 KB
/
Copy pathPyObjectSerializer.cs
File metadata and controls
68 lines (57 loc) · 2.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
using System;
using System.Xml.Linq;
using Python.Runtime;
namespace OpenTap.Python;
/// <summary>
/// Uses Python pickle to serialize any PyObject to base64 and back.
/// This might break in some cases, but it is the best guess we can do.
/// This is for example used for enums.
/// </summary>
public class PyObjectSerializer : ITapSerializerPlugin
{
// Cache module imports to avoid leaking a new PyObject handle per call.
static PyObject _pickle;
static PyObject _codecs;
static PyObject GetPickle() => _pickle ??= Py.Import("pickle");
static PyObject GetCodecs() => _codecs ??= Py.Import("codecs");
public bool Deserialize(XElement node, ITypeData t, Action<object> setter)
{
if (t.DescendsTo(typeof(PyObject)))
{
using (Py.GIL())
{
var pickle = GetPickle();
var codecs = GetCodecs();
// pickle.loads(codecs.decode(node.Value.encode(), "base64"))
using var nodeValuePy = node.Value.ToPython();
using var encoded = nodeValuePy.InvokeMethod("encode");
using var base64Py = "base64".ToPython();
using var decoded = codecs.InvokeMethod("decode", encoded, base64Py);
var val = pickle.InvokeMethod("loads", decoded);
setter(val);
}
return true;
}
return false;
}
public bool Serialize(XElement node, object obj, ITypeData expectedType)
{
if (obj is PyObject py)
{
using (Py.GIL())
{
var pickle = GetPickle();
var codecs = GetCodecs();
// codecs.encode(pickle.dumps(obj), "base64").decode()
using var zeroPy = 0.ToPython();
using var dumped = pickle.InvokeMethod("dumps", py, zeroPy);
using var base64Py = "base64".ToPython();
using var encodedBytes = codecs.InvokeMethod("encode", dumped, base64Py);
using var decodedStr = encodedBytes.InvokeMethod("decode");
node.SetValue(decodedStr);
}
}
return false;
}
public double Order { get; }
}