SourceXtractorPlusPlus  0.16
Please provide a description of the project.
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 
38 namespace py = boost::python;
39 
40 static Elements::Logging logger = Elements::Logging::getLogger("Python::Interpreter");
43 
44 namespace 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 
238 namespace {
239 
240 std::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:63
T size(T... args)
T system_category(T... args)