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