Mercurial > hg > orthanc-python
annotate Sources/PythonLock.cpp @ 213:f8dc8dd2da76
documented orthanc.RegisterIncomingCStoreInstanceFilter() and orthanc.RegisterReceivedInstanceCallback()
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 03 Jul 2024 14:56:51 +0200 |
parents | c8de83fe7faa |
children | 3678a028f1f6 |
rev | line source |
---|---|
0 | 1 /** |
2 * Python plugin for Orthanc | |
166
6fada29b6759
updated copyright, as Orthanc Team now replaces Osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
155
diff
changeset
|
3 * Copyright (C) 2020-2023 Osimis S.A., Belgium |
6fada29b6759
updated copyright, as Orthanc Team now replaces Osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
155
diff
changeset
|
4 * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium |
155
71d305c29cfa
updated year to 2024
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
114
diff
changeset
|
5 * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium |
0 | 6 * |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU Affero General Public License | |
9 * as published by the Free Software Foundation, either version 3 of | |
10 * the License, or (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Affero General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Affero General Public License | |
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 **/ | |
20 | |
21 | |
22 #include "PythonLock.h" | |
23 | |
24 #include "PythonFunction.h" | |
25 #include "PythonModule.h" | |
45
ee76cced46a5
Fix issue #185 (segfaults on non-UTF8 special characters in request URI)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
36
diff
changeset
|
26 #include "PythonString.h" |
0 | 27 |
36
fd58eb5749ed
CMake simplification using DownloadOrthancFramework.cmake
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
28
diff
changeset
|
28 #include "../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h" |
fd58eb5749ed
CMake simplification using DownloadOrthancFramework.cmake
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
28
diff
changeset
|
29 |
fd58eb5749ed
CMake simplification using DownloadOrthancFramework.cmake
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
28
diff
changeset
|
30 #include <Compatibility.h> // For std::unique_ptr<> |
0 | 31 |
32 #include <boost/thread/mutex.hpp> | |
33 | |
34 static boost::mutex mutex_; | |
35 static PyThreadState* interpreterState_ = NULL; | |
36 static PythonLock::ModuleFunctionsInstaller moduleFunctions_ = NULL; | |
37 static PythonLock::ModuleClassesInstaller moduleClasses_ = NULL; | |
38 static std::string moduleName_; | |
39 static std::string exceptionName_; | |
28
b2bbb516056e
The "Calling Python..." info logs are disabled if "PythonVerbose" is "false"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
40 static bool verbose_ = false; |
0 | 41 |
42 | |
43 struct module_state | |
44 { | |
77
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
45 PyObject *exceptionObject_ = NULL; |
0 | 46 }; |
47 | |
48 #if PY_MAJOR_VERSION >= 3 | |
49 # define GETSTATE(module) ((struct module_state*) PyModule_GetState(module)) | |
50 #else | |
51 # define GETSTATE(module) (&_state) | |
52 static struct module_state _state; | |
53 #endif | |
54 | |
55 | |
13 | 56 PythonLock::PythonLock() : |
57 gstate_(PyGILState_Ensure()) | |
0 | 58 { |
171
c8de83fe7faa
removed deprecation warnings
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
59 //ORTHANC_PLUGINS_LOG_INFO("Python lock (GIL) acquired"); |
0 | 60 } |
61 | |
62 | |
63 PythonLock::~PythonLock() | |
64 { | |
65 PyGILState_Release(gstate_); | |
171
c8de83fe7faa
removed deprecation warnings
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
66 //ORTHANC_PLUGINS_LOG_INFO("Python lock (GIL) released"); |
0 | 67 } |
68 | |
69 | |
70 void PythonLock::ExecuteCommand(const std::string& s) | |
71 { | |
72 if (PyRun_SimpleString(s.c_str()) != 0) | |
73 { | |
171
c8de83fe7faa
removed deprecation warnings
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
74 ORTHANC_PLUGINS_LOG_ERROR("Error while executing a Python command"); |
0 | 75 ORTHANC_PLUGINS_THROW_EXCEPTION(Plugin); |
76 } | |
77 } | |
78 | |
79 | |
80 void PythonLock::ExecuteFile(const std::string& path) | |
81 { | |
82 OrthancPlugins::MemoryBuffer buffer; | |
83 buffer.ReadFile(path); | |
84 | |
85 std::string script; | |
86 buffer.ToString(script); | |
87 | |
88 ExecuteCommand(script); | |
89 } | |
90 | |
91 | |
92 bool PythonLock::HasErrorOccurred(std::string& target) | |
93 { | |
94 if (PyErr_Occurred()) | |
95 { | |
96 PyObject *exceptionType = NULL; | |
97 PyObject *exceptionValue = NULL; | |
98 PyObject *traceback = NULL; | |
99 PyErr_Fetch(&exceptionType, &exceptionValue, &traceback); | |
100 | |
101 if (exceptionType == NULL) | |
102 { | |
103 return false; | |
104 } | |
105 | |
106 PyErr_NormalizeException(&exceptionType, &exceptionValue, &traceback); | |
107 | |
108 #if PY_MAJOR_VERSION >= 3 | |
109 if (traceback != NULL) | |
110 { | |
111 PyException_SetTraceback(exceptionValue, traceback); | |
112 } | |
113 #endif | |
114 | |
115 if (exceptionType != NULL) | |
116 { | |
117 PythonObject temp(*this, PyObject_Str(exceptionType)); | |
118 std::string s; | |
119 if (temp.ToUtf8String(s)) | |
120 { | |
121 target += s + "\n"; | |
122 } | |
123 } | |
124 | |
125 if (exceptionValue != NULL) | |
126 { | |
127 PythonObject temp(*this, PyObject_Str(exceptionValue)); | |
128 std::string s; | |
129 if (temp.ToUtf8String(s)) | |
130 { | |
131 target += s + "\n"; | |
132 } | |
133 } | |
134 | |
135 { | |
136 PythonModule module(*this, "traceback"); | |
137 PythonFunction f(*this, module, "format_tb"); | |
138 | |
139 if (traceback != NULL && | |
140 f.IsValid()) | |
141 { | |
142 PythonObject args(*this, PyTuple_New(1)); | |
143 PyTuple_SetItem(args.GetPyObject(), 0, traceback); | |
144 | |
36
fd58eb5749ed
CMake simplification using DownloadOrthancFramework.cmake
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
28
diff
changeset
|
145 std::unique_ptr<PythonObject> value(f.CallUnchecked(args.GetPyObject())); |
0 | 146 |
147 if (value->IsValid()) | |
148 { | |
149 Py_ssize_t len = PyList_Size(value->GetPyObject()); | |
150 for (Py_ssize_t i = 0; i < len; i++) | |
151 { | |
152 PythonObject item(*this, PyList_GetItem(value->GetPyObject(), i), true /* borrowed */); | |
153 std::string line; | |
154 if (item.ToUtf8String(line)) | |
155 { | |
156 target += "\n" + line; | |
157 } | |
158 } | |
159 } | |
160 } | |
161 } | |
162 | |
163 | |
164 /** | |
165 * "This call takes away a reference to each object: you must own | |
166 * a reference to each object before the call and after the call | |
167 * you no longer own these references. (If you don't understand | |
168 * this, don't use this function. I warned you.)" | |
169 * => I don't use PyErr_Restore() | |
170 **/ | |
171 | |
172 //PyErr_Restore(exceptionType, exceptionValue, traceback); | |
173 //PyErr_Clear(); | |
174 | |
175 return true; | |
176 } | |
177 else | |
178 { | |
179 return false; | |
180 } | |
181 } | |
182 | |
183 | |
184 static void RegisterException(PyObject* module, | |
77
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
185 const std::string& fqnName, |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
186 const std::string& shortName) |
0 | 187 { |
188 struct module_state *state = GETSTATE(module); | |
189 | |
77
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
190 state->exceptionObject_ = PyErr_NewException(const_cast<char*>(fqnName.c_str()), NULL, NULL); |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
191 if (state->exceptionObject_ == NULL) |
0 | 192 { |
193 Py_DECREF(module); | |
171
c8de83fe7faa
removed deprecation warnings
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
194 ORTHANC_PLUGINS_LOG_ERROR("Cannot create the Python exception class"); |
0 | 195 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); |
196 } | |
197 | |
77
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
198 Py_XINCREF(state->exceptionObject_); |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
199 if (PyModule_AddObject(module, shortName.c_str(), state->exceptionObject_) < 0) |
0 | 200 { |
77
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
201 Py_XDECREF(state->exceptionObject_); |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
202 Py_CLEAR(state->exceptionObject_); |
171
c8de83fe7faa
removed deprecation warnings
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
203 ORTHANC_PLUGINS_LOG_ERROR("Cannot create the Python exception class"); |
0 | 204 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); |
205 } | |
206 } | |
207 | |
208 | |
209 | |
210 #if PY_MAJOR_VERSION >= 3 | |
211 | |
212 static int sdk_traverse(PyObject *module, visitproc visit, void *arg) | |
213 { | |
77
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
214 Py_VISIT(GETSTATE(module)->exceptionObject_); |
0 | 215 return 0; |
216 } | |
217 | |
218 static int sdk_clear(PyObject *module) | |
219 { | |
77
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
220 Py_CLEAR(GETSTATE(module)->exceptionObject_); |
0 | 221 return 0; |
222 } | |
223 | |
224 static struct PyModuleDef moduledef = | |
225 { | |
226 PyModuleDef_HEAD_INIT, | |
227 NULL, /* m_name => TO BE FILLED */ | |
228 NULL, | |
229 sizeof(struct module_state), | |
230 NULL, /* m_methods => TO BE FILLED */ | |
231 NULL, | |
232 sdk_traverse, | |
233 sdk_clear, | |
234 NULL | |
235 }; | |
236 | |
237 | |
238 PyMODINIT_FUNC InitializeModule() | |
239 { | |
240 if (moduleFunctions_ == NULL || | |
241 moduleClasses_ == NULL || | |
242 moduleName_.empty() || | |
243 exceptionName_.empty()) | |
244 { | |
245 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); | |
246 } | |
247 | |
248 moduledef.m_name = moduleName_.c_str(); | |
249 moduledef.m_methods = moduleFunctions_(); | |
250 | |
251 PyObject *module = PyModule_Create(&moduledef); | |
252 if (module == NULL) | |
253 { | |
171
c8de83fe7faa
removed deprecation warnings
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
254 ORTHANC_PLUGINS_LOG_ERROR("Cannot create a Python module"); |
0 | 255 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); |
256 } | |
257 | |
77
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
258 RegisterException(module, moduleName_ + "." + exceptionName_, exceptionName_); |
0 | 259 moduleClasses_(module); |
260 | |
261 return module; | |
262 } | |
263 | |
264 #else | |
265 | |
266 void InitializeModule() | |
267 { | |
268 if (moduleFunctions_ == NULL || | |
269 moduleClasses_ == NULL || | |
270 moduleName_.empty() || | |
271 exceptionName_.empty()) | |
272 { | |
273 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); | |
274 } | |
275 | |
276 PyObject *module = Py_InitModule(moduleName_.c_str(), moduleFunctions_()); | |
277 if (module == NULL) | |
278 { | |
171
c8de83fe7faa
removed deprecation warnings
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
279 ORTHANC_PLUGINS_LOG_ERROR("Cannot create a Python module"); |
0 | 280 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); |
281 } | |
282 | |
77
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
283 RegisterException(module, moduleName_ + "." + exceptionName_, exceptionName_); |
0 | 284 moduleClasses_(module); |
285 } | |
286 | |
287 #endif | |
288 | |
289 | |
290 | |
63
32de70a1e4c7
New functions from the SDK wrapped in Python: CreateDicom, RegisterFindCallback, RegisterMoveCallback
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
56
diff
changeset
|
291 OrthancPluginErrorCode PythonLock::CheckCallbackSuccess(const std::string& callbackDetails) |
32de70a1e4c7
New functions from the SDK wrapped in Python: CreateDicom, RegisterFindCallback, RegisterMoveCallback
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
56
diff
changeset
|
292 { |
32de70a1e4c7
New functions from the SDK wrapped in Python: CreateDicom, RegisterFindCallback, RegisterMoveCallback
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
56
diff
changeset
|
293 std::string traceback; |
32de70a1e4c7
New functions from the SDK wrapped in Python: CreateDicom, RegisterFindCallback, RegisterMoveCallback
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
56
diff
changeset
|
294 |
32de70a1e4c7
New functions from the SDK wrapped in Python: CreateDicom, RegisterFindCallback, RegisterMoveCallback
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
56
diff
changeset
|
295 if (HasErrorOccurred(traceback)) |
32de70a1e4c7
New functions from the SDK wrapped in Python: CreateDicom, RegisterFindCallback, RegisterMoveCallback
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
56
diff
changeset
|
296 { |
171
c8de83fe7faa
removed deprecation warnings
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
297 ORTHANC_PLUGINS_LOG_ERROR("Error in the " + callbackDetails + ", traceback:\n" + traceback); |
63
32de70a1e4c7
New functions from the SDK wrapped in Python: CreateDicom, RegisterFindCallback, RegisterMoveCallback
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
56
diff
changeset
|
298 return OrthancPluginErrorCode_Plugin; |
32de70a1e4c7
New functions from the SDK wrapped in Python: CreateDicom, RegisterFindCallback, RegisterMoveCallback
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
56
diff
changeset
|
299 } |
32de70a1e4c7
New functions from the SDK wrapped in Python: CreateDicom, RegisterFindCallback, RegisterMoveCallback
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
56
diff
changeset
|
300 else |
32de70a1e4c7
New functions from the SDK wrapped in Python: CreateDicom, RegisterFindCallback, RegisterMoveCallback
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
56
diff
changeset
|
301 { |
32de70a1e4c7
New functions from the SDK wrapped in Python: CreateDicom, RegisterFindCallback, RegisterMoveCallback
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
56
diff
changeset
|
302 return OrthancPluginErrorCode_Success; |
32de70a1e4c7
New functions from the SDK wrapped in Python: CreateDicom, RegisterFindCallback, RegisterMoveCallback
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
56
diff
changeset
|
303 } |
32de70a1e4c7
New functions from the SDK wrapped in Python: CreateDicom, RegisterFindCallback, RegisterMoveCallback
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
56
diff
changeset
|
304 } |
32de70a1e4c7
New functions from the SDK wrapped in Python: CreateDicom, RegisterFindCallback, RegisterMoveCallback
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
56
diff
changeset
|
305 |
32de70a1e4c7
New functions from the SDK wrapped in Python: CreateDicom, RegisterFindCallback, RegisterMoveCallback
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
56
diff
changeset
|
306 |
32de70a1e4c7
New functions from the SDK wrapped in Python: CreateDicom, RegisterFindCallback, RegisterMoveCallback
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
56
diff
changeset
|
307 |
0 | 308 void PythonLock::GlobalInitialize(const std::string& moduleName, |
309 const std::string& exceptionName, | |
310 ModuleFunctionsInstaller moduleFunctions, | |
311 ModuleClassesInstaller moduleClasses, | |
312 bool verbose) | |
313 { | |
314 boost::mutex::scoped_lock lock(mutex_); | |
315 | |
316 if (interpreterState_ != NULL) | |
317 { | |
171
c8de83fe7faa
removed deprecation warnings
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
318 ORTHANC_PLUGINS_LOG_ERROR("Cannot initialize twice the Python interpreter"); |
0 | 319 ORTHANC_PLUGINS_THROW_EXCEPTION(BadSequenceOfCalls); |
320 } | |
321 | |
322 if (moduleClasses == NULL || | |
323 moduleFunctions == NULL) | |
324 { | |
325 ORTHANC_PLUGINS_THROW_EXCEPTION(NullPointer); | |
326 } | |
327 | |
328 if (moduleName.empty() || | |
329 exceptionName.empty()) | |
330 { | |
331 ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); | |
332 } | |
333 | |
334 if (exceptionName.find('.') != std::string::npos) | |
335 { | |
171
c8de83fe7faa
removed deprecation warnings
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
336 ORTHANC_PLUGINS_LOG_ERROR("The name of the exception cannot contain \".\", found: " + exceptionName); |
0 | 337 ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); |
338 } | |
339 | |
340 moduleClasses_ = moduleClasses; | |
341 moduleFunctions_ = moduleFunctions; | |
342 moduleName_ = moduleName; | |
343 exceptionName_ = exceptionName; | |
344 | |
345 std::string executable; | |
346 | |
347 { | |
348 OrthancPlugins::OrthancString str; | |
349 str.Assign(OrthancPluginGetOrthancPath(OrthancPlugins::GetGlobalContext())); | |
350 str.ToString(executable); | |
351 } | |
352 | |
171
c8de83fe7faa
removed deprecation warnings
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
353 ORTHANC_PLUGINS_LOG_WARNING("Program name: " + executable); |
0 | 354 |
355 #if PY_MAJOR_VERSION == 2 | |
356 Py_SetProgramName(&executable[0]); /* optional but recommended */ | |
357 #else | |
358 std::wstring wide(executable.begin(), executable.end()); | |
359 Py_SetProgramName(&wide[0]); /* optional but recommended */ | |
360 Py_UnbufferedStdioFlag = 1; // Write immediately to stdout after "sys.stdout.flush()" (only in Python 3.x) | |
361 #endif | |
362 | |
363 Py_InspectFlag = 1; // Don't exit the Orthanc process on Python error | |
364 | |
28
b2bbb516056e
The "Calling Python..." info logs are disabled if "PythonVerbose" is "false"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
365 verbose_ = verbose; |
0 | 366 if (verbose) |
367 { | |
368 Py_VerboseFlag = 1; | |
369 } | |
370 | |
371 #if PY_MAJOR_VERSION >= 3 | |
372 PyImport_AppendInittab(moduleName_.c_str(), InitializeModule); | |
373 #endif | |
374 | |
375 #if PY_VERSION_HEX < 0x03020000 /* 3.2.0 */ | |
376 /** | |
377 * "Changed in version 3.2: This function cannot be called before | |
378 * Py_Initialize() anymore." | |
379 **/ | |
380 if (!PyEval_ThreadsInitialized()) | |
381 { | |
382 PyEval_InitThreads(); | |
383 } | |
384 #endif | |
385 | |
386 Py_InitializeEx(0 /* Python is embedded, skip signal handlers */); | |
387 | |
12 | 388 #if 0 |
0 | 389 #if PY_MAJOR_VERSION == 2 |
390 std::cout << Py_GetPath() << std::endl; | |
391 std::cout << Py_GetProgramName() << std::endl; | |
392 std::cout << Py_GetProgramFullPath() << std::endl; | |
393 #else | |
394 std::wcout << Py_GetPath() << std::endl; | |
395 std::wcout << Py_GetProgramName() << std::endl; | |
396 std::wcout << Py_GetProgramFullPath() << std::endl; | |
397 #endif | |
12 | 398 #endif |
0 | 399 |
400 #if (PY_VERSION_HEX >= 0x03020000 /* 3.2.0 */ && \ | |
401 PY_VERSION_HEX < 0x03070000 /* 3.7.0 */) | |
402 /** | |
403 * Changed in version 3.7: This function is now called by | |
404 * Py_Initialize(), so you don't have to call it yourself anymore. | |
405 **/ | |
406 if (!PyEval_ThreadsInitialized()) | |
407 { | |
408 PyEval_InitThreads(); | |
409 } | |
410 #endif | |
411 | |
412 | |
413 #if PY_MAJOR_VERSION == 2 | |
414 InitializeModule(); | |
415 #endif | |
416 | |
417 // https://fr.slideshare.net/YiLungTsai/embed-python => slide 26 | |
418 interpreterState_ = PyEval_SaveThread(); | |
419 } | |
420 | |
421 | |
422 void PythonLock::AddSysPath(const std::string& path) | |
423 { | |
424 /** | |
425 * "It is recommended that applications embedding the Python | |
426 * interpreter for purposes other than executing a single script | |
427 * pass 0 as updatepath, and update sys.path themselves if | |
428 * desired. See CVE-2008-5983." | |
429 * => Set "sys.path.append()" to the directory of the configuration file by default | |
430 **/ | |
431 | |
432 PythonLock lock; | |
433 | |
434 /** | |
435 * Initialization of "sys.path.append()" must be done before loading | |
436 * any module. | |
437 **/ | |
438 | |
439 PyObject *sysPath = PySys_GetObject(const_cast<char*>("path")); | |
440 if (sysPath == NULL) | |
441 { | |
171
c8de83fe7faa
removed deprecation warnings
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
442 ORTHANC_PLUGINS_LOG_ERROR("Cannot find sys.path"); |
0 | 443 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); |
444 } | |
445 | |
45
ee76cced46a5
Fix issue #185 (segfaults on non-UTF8 special characters in request URI)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
36
diff
changeset
|
446 PythonString pyPath(lock, path); |
ee76cced46a5
Fix issue #185 (segfaults on non-UTF8 special characters in request URI)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
36
diff
changeset
|
447 int result = PyList_Insert(sysPath, 0, pyPath.Release()); |
0 | 448 |
449 if (result != 0) | |
450 { | |
171
c8de83fe7faa
removed deprecation warnings
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
451 ORTHANC_PLUGINS_LOG_ERROR("Cannot run sys.path.append()"); |
0 | 452 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); |
453 } | |
454 } | |
455 | |
456 | |
457 void PythonLock::GlobalFinalize() | |
458 { | |
459 boost::mutex::scoped_lock lock(mutex_); | |
460 | |
461 if (interpreterState_ != NULL) | |
462 { | |
463 PyEval_RestoreThread(interpreterState_); | |
464 interpreterState_ = NULL; | |
465 } | |
466 | |
467 Py_Finalize(); | |
468 } | |
469 | |
470 | |
75
cbfc72a53970
refactoring calls to PythonLock::RaiseException()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
63
diff
changeset
|
471 void PythonLock::RaiseException(OrthancPluginErrorCode code) |
0 | 472 { |
473 if (code != OrthancPluginErrorCode_Success) | |
474 { | |
77
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
475 if (0) |
0 | 476 { |
77
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
477 // This was the implementation in versions <= 3.2 of the Python plugin |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
478 PyErr_SetString(PyExc_ValueError, "Internal error"); |
0 | 479 } |
480 else | |
481 { | |
77
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
482 // "Python custom exceptions in C(++) extensions" |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
483 // https://www.pierov.org/2020/03/01/python-custom-exceptions-c-extensions/ |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
484 |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
485 const char* message = OrthancPluginGetErrorDescription(OrthancPlugins::GetGlobalContext(), code); |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
486 |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
487 PythonLock lock; |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
488 |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
489 #if PY_MAJOR_VERSION >= 3 |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
490 PythonModule module(lock, moduleName_); |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
491 #endif |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
492 |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
493 struct module_state *state = GETSTATE(module.GetPyObject()); |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
494 if (state->exceptionObject_ == NULL) |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
495 { |
171
c8de83fe7faa
removed deprecation warnings
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
496 ORTHANC_PLUGINS_LOG_ERROR("No Python exception has been registered"); |
77
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
497 } |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
498 else |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
499 { |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
500 PythonString str(lock, message); |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
501 |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
502 PyObject *exception = PyTuple_New(2); |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
503 PyTuple_SetItem(exception, 0, PyLong_FromLong(code)); |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
504 PyTuple_SetItem(exception, 1, str.Release()); |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
505 PyErr_SetObject(state->exceptionObject_, exception); |
e7ff5efb100d
Custom exception "orthanc.OrthancException" is raised instead of "ValueError"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
75
diff
changeset
|
506 } |
0 | 507 } |
508 } | |
509 } | |
28
b2bbb516056e
The "Calling Python..." info logs are disabled if "PythonVerbose" is "false"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
510 |
b2bbb516056e
The "Calling Python..." info logs are disabled if "PythonVerbose" is "false"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
511 |
b2bbb516056e
The "Calling Python..." info logs are disabled if "PythonVerbose" is "false"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
512 void PythonLock::LogCall(const std::string& message) |
b2bbb516056e
The "Calling Python..." info logs are disabled if "PythonVerbose" is "false"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
513 { |
b2bbb516056e
The "Calling Python..." info logs are disabled if "PythonVerbose" is "false"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
514 /** |
b2bbb516056e
The "Calling Python..." info logs are disabled if "PythonVerbose" is "false"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
515 * For purity, this function should lock the global "mutex_", but |
b2bbb516056e
The "Calling Python..." info logs are disabled if "PythonVerbose" is "false"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
516 * "verbose_" cannot change after the initial call to |
b2bbb516056e
The "Calling Python..." info logs are disabled if "PythonVerbose" is "false"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
517 * "GlobalInitialize()". |
b2bbb516056e
The "Calling Python..." info logs are disabled if "PythonVerbose" is "false"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
518 **/ |
b2bbb516056e
The "Calling Python..." info logs are disabled if "PythonVerbose" is "false"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
519 |
b2bbb516056e
The "Calling Python..." info logs are disabled if "PythonVerbose" is "false"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
520 if (verbose_) |
b2bbb516056e
The "Calling Python..." info logs are disabled if "PythonVerbose" is "false"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
521 { |
171
c8de83fe7faa
removed deprecation warnings
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
522 ORTHANC_PLUGINS_LOG_INFO(message); |
28
b2bbb516056e
The "Calling Python..." info logs are disabled if "PythonVerbose" is "false"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
523 } |
b2bbb516056e
The "Calling Python..." info logs are disabled if "PythonVerbose" is "false"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
524 } |