-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathPythonProxy.cpp
More file actions
173 lines (150 loc) · 5.14 KB
/
PythonProxy.cpp
File metadata and controls
173 lines (150 loc) · 5.14 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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// Copyright (c) 2013-2020 Josh Blum
// 2021 Nicholas Corgan
// SPDX-License-Identifier: BSL-1.0
#include "PythonSupport.hpp"
#include "PythonProxy.hpp"
#include <Pothos/Plugin.hpp>
#include <Pothos/Callable.hpp>
#include <Poco/SingletonHolder.h>
#include <Pothos/System/Paths.hpp>
#include <Poco/Path.h>
/***********************************************************************
* Per process Python interp init and cleanup
**********************************************************************/
struct PythonInterpWrapper
{
PythonInterpWrapper(void):
_s(nullptr)
{
Py_Initialize();
#if PY_VERSION_HEX < 0x03070000
// Python 3.7: automatically called by Py_Initialize()
// Python 3.9: deprecated, does nothing
// Python 3.11: removed
PyEval_InitThreads();
#endif
_s = PyEval_SaveThread();
}
~PythonInterpWrapper(void)
{
PyEval_RestoreThread(_s);
Py_Finalize();
}
PyThreadState *_s;
};
static PythonInterpWrapper &getPythonInterpWrapper(void)
{
static Poco::SingletonHolder<PythonInterpWrapper> sh;
return *sh.get();
}
/***********************************************************************
* PythonProxyEnvironment methods
**********************************************************************/
PythonProxyEnvironment::PythonProxyEnvironment(const Pothos::ProxyEnvironmentArgs &)
{
return;
}
Pothos::Proxy PythonProxyEnvironment::makeHandle(PyObject *obj, const bool borrowed)
{
auto env = std::dynamic_pointer_cast<PythonProxyEnvironment>(this->shared_from_this());
return Pothos::Proxy(new PythonProxyHandle(env, obj, borrowed));
}
Pothos::Proxy PythonProxyEnvironment::makeHandle(const PyObjectRef &ref)
{
return this->makeHandle(ref.obj, REF_BORROWED);
}
std::shared_ptr<PythonProxyHandle> PythonProxyEnvironment::getHandle(const Pothos::Proxy &proxy)
{
PyGilStateLock lock;
Pothos::Proxy myProxy = proxy;
if (proxy.getEnvironment() != this->shared_from_this())
{
myProxy = this->convertObjectToProxy(proxy.toObject());
}
auto handle = std::dynamic_pointer_cast<PythonProxyHandle>(myProxy.getHandle());
assert(handle);
return handle;
}
Pothos::Proxy PythonProxyEnvironment::findProxy(const std::string &name)
{
PyGilStateLock lock;
PyObjectRef module(PyImport_ImportModule(name.c_str()), REF_NEW);
if (module.obj == nullptr) throw Pothos::ProxyEnvironmentFindError(
"PythonProxyEnvironment::findProxy("+name+")", getErrorString());
return this->makeHandle(module);
}
Pothos::Proxy PythonProxyEnvironment::convertObjectToProxy(const Pothos::Object &local)
{
PyGilStateLock lock;
try
{
return Pothos::ProxyEnvironment::convertObjectToProxy(local);
}
catch (const Pothos::ProxyEnvironmentConvertError &)
{
auto env = Pothos::ProxyEnvironment::make("managed");
auto proxy = env->convertObjectToProxy(local);
return this->makeProxy(proxy);
}
}
Pothos::Object PythonProxyEnvironment::convertProxyToObject(const Pothos::Proxy &proxy)
{
PyGilStateLock lock;
auto r = Pothos::ProxyEnvironment::convertProxyToObject(proxy);
if (r.type() == typeid(Pothos::Object)) return r.extract<Pothos::Object>();
return r;
}
void PythonProxyEnvironment::serialize(const Pothos::Proxy &proxy, std::ostream &os)
{
try
{
auto marshal = this->findProxy("marshal");
const std::vector<char> data = marshal.call("dumps", proxy);
os.write(data.data(), data.size());
}
catch (const Pothos::Exception &ex)
{
throw Pothos::ProxySerializeError("PythonProxyEnvironment::serialize()", ex);
}
}
Pothos::Proxy PythonProxyEnvironment::deserialize(std::istream &is)
{
is.seekg (0, std::ios_base::end);
const auto length = is.tellg();
is.seekg (0, std::ios_base::beg);
std::vector<char> bytes(length);
is.read(bytes.data(), bytes.size());
try
{
auto marshal = this->findProxy("marshal");
return marshal.call("loads", bytes);
}
catch (const Pothos::Exception &ex)
{
throw Pothos::ProxySerializeError("PythonProxyEnvironment::deserialize()", ex);
}
}
/***********************************************************************
* factory registration
**********************************************************************/
Pothos::ProxyEnvironment::Sptr makePythonProxyEnvironment(const Pothos::ProxyEnvironmentArgs &args)
{
auto env = Pothos::ProxyEnvironment::Sptr(new PythonProxyEnvironment(args));
//The interpreter might already be initialized if python is the caller
if (Py_IsInitialized()) return env;
getPythonInterpWrapper();
auto sys = env->findProxy("sys");
sys.call("set:dont_write_bytecode", true);
Poco::Path pythonPath(Pothos::System::getRootPath());
pythonPath.append(POTHOS_PYTHON_DIR);
auto sysPath = sys.call("get:path");
sysPath.call("append", pythonPath.toString());
env->findProxy("Pothos"); //registers important converters
return env;
}
pothos_static_block(pothosRegisterPythonProxy)
{
Pothos::PluginRegistry::addCall(
"/proxy/environment/python",
&makePythonProxyEnvironment);
}