SourceXtractorPlusPlus 0.18
SourceXtractor++, the next generation SExtractor
PythonInterpreter.cpp
Go to the documentation of this file.
1
17/*
18 * @file PythonInterpreter.cpp
19 * @author Nikolaos Apostolakos <nikoapos@gmail.com>
20 */
21
22#include <signal.h>
23#include <fstream>
24#include <system_error>
25#include <utility>
26#include <boost/python/dict.hpp>
27#include <boost/python/exec.hpp>
28#include <boost/python/extract.hpp>
29#include <boost/python/import.hpp>
30#include <boost/python/object.hpp>
31#include <Python.h>
34#include <Pyston/GIL.h>
35#include <Pyston/Exceptions.h>
36#include <Pyston/Module.h>
37
38namespace py = boost::python;
39
43
44namespace SourceXtractor {
45
47 static PythonInterpreter singleton{};
48 return singleton;
49}
50
52 // Python sets its own signal handler for SIGINT (Ctrl+C), so it can throw a KeyboardInterrupt
53 // Here we are not interested on this behaviour, so we get whatever handler we've got (normally
54 // the default one) and restore it after initializing the interpreter
55 struct sigaction sigint_handler;
56 sigaction(SIGINT, nullptr, &sigint_handler);
57
58 PyImport_AppendInittab("pyston", PYSTON_MODULE_INIT);
59 Py_Initialize();
60 PyEval_InitThreads();
61 PyEval_SaveThread();
62
63 sigaction(SIGINT, &sigint_handler, nullptr);
64}
65
67 logger.info() << "Python GIL acquired " << Pyston::GILLocker::getLockCount() << " times";
68}
69
71 Pyston::GILLocker locker;
72
73 py::object main_module = py::import("__main__");
74 py::object main_namespace = main_module.attr("__dict__");
75 try {
76 py::exec(code.c_str(), main_namespace);
77 }
78 catch (const py::error_already_set &e) {
79 throw Pyston::Exception().log(log4cpp::Priority::ERROR, logger);
80 }
81}
82
84 Pyston::GILLocker locker;
85
86 try {
87 // Setup argv
88 // Python expects to have the ownership!
89#if PY_MAJOR_VERSION == 2
90 using py_argv_char_t = char;
91# define py_argv_assign(d, s, l) d = strndup(s, l)
92#else
93 using py_argv_char_t = wchar_t;
94# define py_argv_assign(d, s, l) d = Py_DecodeLocale(s, &(l))
95#endif
96
97 py_argv_char_t **py_argv = static_cast<py_argv_char_t**>(PyMem_MALLOC((argv.size() + 1) * sizeof(py_argv_char_t*)));
98 size_t wlen = filename.size();
99 py_argv_assign(py_argv[0], filename.c_str(), wlen);
100 for (size_t i = 0; i < argv.size(); ++i) {
101 wlen = argv[i].size();
102 py_argv_assign(py_argv[i + 1], argv[i].c_str(), wlen);
103 }
104 PySys_SetArgv(argv.size() + 1, py_argv);
105
106 // Import ourselves so the conversions are registered
107 py::import("_SourceXtractorPy");
108
109 // Setup stdout and stderr
110 PySys_SetObject("stdout", py::object(boost::ref(m_out_wrapper)).ptr());
111 PySys_SetObject("stderr", py::object(boost::ref(m_err_wrapper)).ptr());
112
113 // Run the file
114 py::object main_module = py::import("__main__");
115 py::setattr(main_module, "__file__", py::object(filename));
116 py::object main_namespace = main_module.attr("__dict__");
117
118 // boost 1.75 up to 1.77 has a bug that trashes the heap
119 // See https://github.com/boostorg/python/issues/371
120 // So we read the file ourselves as a workaround
122 if (fs.fail()) {
124 }
126 py::exec(pycode.c_str(), main_namespace);
127 }
128 catch (const py::error_already_set &e) {
129 throw Pyston::Exception().log(log4cpp::Priority::ERROR, logger);
130 }
131 catch (const std::system_error& e) {
132 throw Elements::Exception() << e.what() << ": " << e.code().message();
133 }
134}
135
137 Pyston::GILLocker locker;
138
139 try {
140 py::object meas_images_module = py::import("sourcextractor.config.measurement_images");
141 py::dict images = py::extract<py::dict>(meas_images_module.attr("measurement_images"));
142 py::list ids = images.keys();
144 for (int i = 0; i < py::len(ids); ++i) {
145 int id = py::extract<int>(ids[i]);
146 PyMeasurementImage im = py::extract<PyMeasurementImage>(images[ids[i]]);
147 result.emplace(std::make_pair(id, im));
148 }
149 return result;
150 }
151 catch (const py::error_already_set &e) {
152 throw Pyston::Exception().log(log4cpp::Priority::ERROR, logger);
153 }
154}
155
157 Pyston::GILLocker locker;
158
159 try {
160 py::object apertures_module = py::import("sourcextractor.config.aperture");
161 py::dict apertures = py::extract<py::dict>(apertures_module.attr("apertures_for_image"));
162 py::list ids = apertures.keys();
164 for (int i = 0; i < py::len(ids); ++i) {
165 int id = py::extract<int>(ids[i]);
166 PyAperture ap = py::extract<PyAperture>(apertures[ids[i]]);
167 result.emplace(std::make_pair(id, ap));
168 }
169 return result;
170 }
171 catch (const py::error_already_set &e) {
172 throw Pyston::Exception().log(log4cpp::Priority::ERROR, logger);
173 }
174}
175
177 Pyston::GILLocker locker;
178
179 try {
180 py::object output_module = py::import("sourcextractor.config.output");
181 py::list output = py::extract<py::list>(output_module.attr("model_fitting_parameter_columns"));
183 for (int i = 0; i < py::len(output); ++i) {
184 py::tuple t = py::extract<py::tuple>(output[i]);
185 std::string name = py::extract<std::string>(t[0]);
186 auto extract_list = py::extract<py::list>(t[1]);
187
188 std::vector<int> ids{};
189 if (extract_list.check()) {
190 py::list cs = extract_list;
191 for (int j = 0; j < py::len(cs); ++j) {
192 int c = py::extract<int>(cs[j].attr("id"));
193 ids.push_back(c);
194 }
195 } else {
196 int c = py::extract<int>(t[1]);
197 ids.push_back(c);
198 }
199 result.emplace_back(name, std::move(ids));
200 }
201 return result;
202 }
203 catch (const py::error_already_set &e) {
204 throw Pyston::Exception().log(log4cpp::Priority::ERROR, logger);
205 }
206}
207
209 Pyston::GILLocker locker;
210
211 try {
212 py::object output_module = py::import("sourcextractor.config.output");
213 py::list output = py::extract<py::list>(output_module.attr("aperture_columns"));
215 for (int i = 0; i < py::len(output); ++i) {
216 py::tuple t = py::extract<py::tuple>(output[i]);
217 std::string name = py::extract<std::string>(t[0]);
218 auto extract_list = py::extract<py::list>(t[1]);
219
220 if (extract_list.check()) {
221 py::list cs = extract_list;
222 for (int j = 0; j < py::len(cs); ++j) {
223 int c = py::extract<int>(cs[j].attr("id"));
224 result[name].push_back(c);
225 }
226 } else {
227 int c = py::extract<int>(t[1]);
228 result[name].push_back(c);
229 }
230 }
231 return result;
232 }
233 catch (const py::error_already_set &e) {
234 throw Pyston::Exception().log(log4cpp::Priority::ERROR, logger);
235 }
236}
237
238namespace {
239
240std::map<int, boost::python::object> getMapFromDict(const py::str &module_name, const py::str &dict_name) {
241 Pyston::GILLocker locker;
242
243 try {
244 py::object model_fitting_module = py::import(module_name);
245 py::dict parameters = py::extract<py::dict>(model_fitting_module.attr(dict_name));
246 py::list ids = parameters.keys();
248 for (int i = 0; i < py::len(ids); ++i) {
249 int id = py::extract<int>(ids[i]);
250 auto par = parameters[ids[i]];
251 result.emplace(std::make_pair(id, par));
252 }
253 return result;
254 }
255 catch (const py::error_already_set &e) {
256 throw Pyston::Exception().log(log4cpp::Priority::ERROR, logger);
257 }
258}
259
260}
261
263 return getMapFromDict("sourcextractor.config.model_fitting", "constant_parameter_dict");
264}
265
267 return getMapFromDict("sourcextractor.config.model_fitting", "free_parameter_dict");
268}
269
271 return getMapFromDict("sourcextractor.config.model_fitting", "dependent_parameter_dict");
272}
273
275 return getMapFromDict("sourcextractor.config.model_fitting", "prior_dict");
276}
277
279 return getMapFromDict("sourcextractor.config.model_fitting", "constant_model_dict");
280}
281
283 return getMapFromDict("sourcextractor.config.model_fitting", "point_source_model_dict");
284}
285
287 return getMapFromDict("sourcextractor.config.model_fitting", "sersic_model_dict");
288}
289
291 return getMapFromDict("sourcextractor.config.model_fitting", "exponential_model_dict");
292}
293
295 return getMapFromDict("sourcextractor.config.model_fitting", "de_vaucouleurs_model_dict");
296}
297
299 return getMapFromDict("sourcextractor.config.model_fitting", "onnx_model_dict");
300}
301
303 Pyston::GILLocker locker;
304 try {
306 py::object model_fitting_module = py::import("sourcextractor.config.model_fitting");
307 py::dict frame_dict = py::extract<py::dict>(model_fitting_module.attr("frame_models_dict"));
308 py::list frame_ids = frame_dict.keys();
309 for (int i = 0; i < py::len(frame_ids); ++i) {
310 int frame_id = py::extract<int>(frame_ids[i]);
311 py::list model_ids = py::extract<py::list>(frame_dict[frame_ids[i]]);
312 for (int j = 0; j < py::len(model_ids); ++j) {
313 int model_id = py::extract<int>(model_ids[j]);
314 result[frame_id].push_back(model_id);
315 }
316 }
317 return result;
318 }
319 catch (const py::error_already_set &e) {
320 throw Pyston::Exception().log(log4cpp::Priority::ERROR, logger);
321 }
322}
323
325 Pyston::GILLocker locker;
326
327 py::object model_fitting_module = py::import("sourcextractor.config.model_fitting");
328 py::dict parameters = py::extract<py::dict>(model_fitting_module.attr("params_dict"));
329 py::list ids = parameters.keys();
331 for (int i = 0; i < py::len(ids); ++i) {
332 std::string id = py::extract<std::string>(ids[i]);
333 auto par = parameters[ids[i]];
334 result.emplace(std::make_pair(id, par));
335 }
336 return result;
337}
338
340 Pyston::GILLocker locker;
341
342 try {
343 py::object model_fitting_module = py::import("sourcextractor.config.measurement_images");
344 py::list groups = py::extract<py::list>(model_fitting_module.attr("MeasurementGroup").attr("_all_groups"));
346 for (int i = 0; i < py::len(groups); ++i) {
347 result.emplace_back(groups[i]);
348 }
349 return result;
350 }
351 catch (const py::error_already_set &e) {
352 throw Pyston::Exception().log(log4cpp::Priority::ERROR, logger);
353 }
354}
355
357 Pyston::GILLocker locker;
358
359 py::object model_fitting_module = py::import("sourcextractor.config.model_fitting");
360 auto python_function = model_fitting_module.attr("set_coordinate_system");
361 python_function(coordinate_system);
362}
363
364}
#define PYSTON_MODULE_INIT
static Elements::Logging stdout_logger
#define py_argv_assign(d, s, l)
static Elements::Logging logger
static Elements::Logging stderr_logger
T c_str(T... args)
static Logging getLogger(const std::string &name="")
const Exception & log(log4cpp::Priority::Value level, Elements::Logging &logger) const
static size_t getLockCount()
std::map< int, boost::python::object > getDeVaucouleursModels()
std::vector< boost::python::object > getMeasurementGroups()
std::map< int, PyAperture > getApertures()
std::map< std::string, std::vector< int > > getApertureOutputColumns()
std::map< int, boost::python::object > getDependentParameters()
std::vector< std::pair< std::string, std::vector< int > > > getModelFittingOutputColumns()
std::map< int, boost::python::object > getSersicModels()
std::map< int, boost::python::object > getPriors()
std::map< int, boost::python::object > getFreeParameters()
static PythonInterpreter & getSingleton()
void runCode(const std::string &code)
std::map< int, boost::python::object > getOnnxModels()
std::map< int, boost::python::object > getExponentialModels()
std::map< int, boost::python::object > getConstantParameters()
void runFile(const std::string &filename, const std::vector< std::string > &argv)
std::map< int, boost::python::object > getConstantModels()
std::map< int, std::vector< int > > getFrameModelsMap()
std::map< int, PyMeasurementImage > getMeasurementImages()
std::map< int, boost::python::object > getPointSourceModels()
void setCoordinateSystem(std::shared_ptr< CoordinateSystem > coordinate_system)
std::map< std::string, boost::python::object > getModelFittingParams()
T emplace_back(T... args)
T emplace(T... args)
T fail(T... args)
T make_pair(T... args)
T move(T... args)
constexpr double e
static auto logger
Definition: WCS.cpp:44
string filename
Definition: conf.py:65
T size(T... args)
T system_category(T... args)