SourceXtractorPlusPlus 0.21
SourceXtractor++, the next generation SExtractor
Loading...
Searching...
No Matches
PythonInterpreter.cpp
Go to the documentation of this file.
1/*
2 * Copyright © 2019-2022 Université de Genève, LMU Munich - Faculty of Physics, IAP-CNRS/Sorbonne Université
3 *
4 * This library is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License as published by the Free
6 * Software Foundation; either version 3.0 of the License, or (at your option)
7 * any later version.
8 *
9 * This library is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 * details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18/*
19 * @file PythonInterpreter.cpp
20 * @author Nikolaos Apostolakos <nikoapos@gmail.com>
21 */
22
23#include <Pyston/Exceptions.h>
24#include <Pyston/GIL.h>
25#include <Pyston/Module.h>
26#include <Python.h>
29#include <boost/python/dict.hpp>
30#include <boost/python/exec.hpp>
31#include <boost/python/extract.hpp>
32#include <boost/python/import.hpp>
33#include <boost/python/object.hpp>
34#include <fstream>
35#include <signal.h>
36#include <system_error>
37#include <utility>
38
39namespace py = boost::python;
40
44
45namespace SourceXtractor {
46
51
53 // Python sets its own signal handler for SIGINT (Ctrl+C), so it can throw a KeyboardInterrupt
54 // Here we are not interested on this behaviour, so we get whatever handler we've got (normally
55 // the default one) and restore it after initializing the interpreter
58
61#if PY_VERSION_HEX < 3090000
63#endif
65
67}
68
70 logger.info() << "Python GIL acquired " << Pyston::GILLocker::getLockCount() << " times";
71}
72
75
76 try {
77 // Setup argv
78 // Python expects to have the ownership!
79#if PY_MAJOR_VERSION == 2
80 using py_argv_char_t = char;
81#define py_argv_assign(d, s, l) d = strndup(s, l)
82#else
83 using py_argv_char_t = wchar_t;
84#define py_argv_assign(d, s, l) d = Py_DecodeLocale(s, &(l))
85#endif
86
87 py_argv_char_t** py_argv = static_cast<py_argv_char_t**>(PyMem_MALLOC((argv.size() + 1) * sizeof(py_argv_char_t*)));
88 size_t wlen = filename.size();
89 py_argv_assign(py_argv[0], filename.c_str(), wlen);
90 for (size_t i = 0; i < argv.size(); ++i) {
91 wlen = argv[i].size();
92 py_argv_assign(py_argv[i + 1], argv[i].c_str(), wlen);
93 }
94 PySys_SetArgv(argv.size() + 1, py_argv);
95
96 // Import ourselves so the conversions are registered
97 py::import("_SourceXtractorPy");
98
99 // Setup stdout and stderr
100 PySys_SetObject("stdout", py::object(boost::ref(m_out_wrapper)).ptr());
101 PySys_SetObject("stderr", py::object(boost::ref(m_err_wrapper)).ptr());
102
103 // Run the file
104 py::object main_module = py::import("__main__");
105 py::setattr(main_module, "__file__", py::object(filename));
106 py::object main_namespace = main_module.attr("__dict__");
107
108 // boost 1.75 up to 1.77 has a bug that trashes the heap
109 // See https://github.com/boostorg/python/issues/371
110 // So we read the file ourselves as a workaround
111 std::ifstream fs(filename);
112 if (fs.fail()) {
113 throw std::system_error(errno, std::system_category(), filename);
114 }
116 py::exec(pycode.c_str(), main_namespace);
117 } catch (const py::error_already_set& e) {
118 throw Pyston::Exception().log(log4cpp::Priority::ERROR, logger);
119 } catch (const std::system_error& e) {
120 throw Elements::Exception() << e.what() << ": " << e.code().message();
121 }
122}
123
126 try {
127 m_measurement_config = py::import("sourcextractor.config.measurement_config").attr("global_measurement_config");
128 } catch (const py::error_already_set& e) {
129 throw Pyston::Exception().log(log4cpp::Priority::ERROR, logger);
130 }
131}
132
135
136 try {
137 py::dict images = py::extract<py::dict>(m_measurement_config.attr("measurement_images"));
138 py::list ids = images.keys();
140 for (int i = 0; i < py::len(ids); ++i) {
141 int id = py::extract<int>(ids[i]);
142 PyMeasurementImage im = py::extract<PyMeasurementImage>(images[ids[i]]);
143 result.emplace(std::make_pair(id, im));
144 }
145 return result;
146 } catch (const py::error_already_set& e) {
147 throw Pyston::Exception().log(log4cpp::Priority::ERROR, logger);
148 }
149}
150
153
154 try {
155 py::dict apertures = py::extract<py::dict>(m_measurement_config.attr("apertures_for_image"));
156 py::list ids = apertures.keys();
158 for (int i = 0; i < py::len(ids); ++i) {
159 int id = py::extract<int>(ids[i]);
160 PyAperture ap = py::extract<PyAperture>(apertures[ids[i]]);
161 result.emplace(std::make_pair(id, ap));
162 }
163 return result;
164 } catch (const py::error_already_set& e) {
165 throw Pyston::Exception().log(log4cpp::Priority::ERROR, logger);
166 }
167}
168
171
172 try {
173 py::list output = py::extract<py::list>(m_measurement_config.attr("model_fitting_parameter_columns"));
175 for (int i = 0; i < py::len(output); ++i) {
176 py::tuple t = py::extract<py::tuple>(output[i]);
177 std::string name = py::extract<std::string>(t[0]);
178 auto extract_list = py::extract<py::list>(t[1]);
179
181 if (extract_list.check()) {
182 py::list cs = extract_list;
183 for (int j = 0; j < py::len(cs); ++j) {
184 int c = py::extract<int>(cs[j].attr("id"));
185 ids.push_back(c);
186 }
187 } else {
188 int c = py::extract<int>(t[1]);
189 ids.push_back(c);
190 }
191 result.emplace_back(name, std::move(ids));
192 }
193 return result;
194 } catch (const py::error_already_set& e) {
195 throw Pyston::Exception().log(log4cpp::Priority::ERROR, logger);
196 }
197}
198
201
202 try {
203 py::list output = py::extract<py::list>(m_measurement_config.attr("aperture_columns"));
205 for (int i = 0; i < py::len(output); ++i) {
206 py::tuple t = py::extract<py::tuple>(output[i]);
207 std::string name = py::extract<std::string>(t[0]);
208 auto extract_list = py::extract<py::list>(t[1]);
209
210 if (extract_list.check()) {
211 py::list cs = extract_list;
212 for (int j = 0; j < py::len(cs); ++j) {
213 int c = py::extract<int>(cs[j].attr("id"));
214 result[name].push_back(c);
215 }
216 } else {
217 int c = py::extract<int>(t[1]);
218 result[name].push_back(c);
219 }
220 }
221 return result;
222 } catch (const py::error_already_set& e) {
223 throw Pyston::Exception().log(log4cpp::Priority::ERROR, logger);
224 }
225}
226
228 const char* dict_name) {
230
231 try {
232 py::object obj = m_measurement_config.attr(object_name);
233 py::dict parameters = py::extract<py::dict>(obj.attr(dict_name));
234 py::list ids = parameters.keys();
235
237 for (int i = 0; i < py::len(ids); ++i) {
238 int id = py::extract<int>(ids[i]);
239 auto par = parameters[ids[i]];
240 result.emplace(std::make_pair(id, par));
241 }
242 return result;
243 } catch (const py::error_already_set& e) {
244 throw Pyston::Exception().log(log4cpp::Priority::ERROR, logger);
245 }
246}
247
249 return getMapFromDict("model_fitting", "constant_parameter_dict");
250}
251
253 return getMapFromDict("model_fitting", "free_parameter_dict");
254}
255
257 return getMapFromDict("model_fitting", "dependent_parameter_dict");
258}
259
261 return getMapFromDict("model_fitting", "prior_dict");
262}
263
265 return getMapFromDict("model_fitting", "constant_model_dict");
266}
267
269 return getMapFromDict("model_fitting", "point_source_model_dict");
270}
271
273 return getMapFromDict("model_fitting", "sersic_model_dict");
274}
275
277 return getMapFromDict("model_fitting", "exponential_model_dict");
278}
279
281 return getMapFromDict("model_fitting", "de_vaucouleurs_model_dict");
282}
283
285 return getMapFromDict("model_fitting", "onnx_model_dict");
286}
287
290 try {
292 py::object model_fitting = m_measurement_config.attr("model_fitting");
293 py::dict frame_dict = py::extract<py::dict>(model_fitting.attr("frame_models_dict"));
294 py::list frame_ids = frame_dict.keys();
295 for (int i = 0; i < py::len(frame_ids); ++i) {
296 int frame_id = py::extract<int>(frame_ids[i]);
297 py::list model_ids = py::extract<py::list>(frame_dict[frame_ids[i]]);
298 for (int j = 0; j < py::len(model_ids); ++j) {
299 int model_id = py::extract<int>(model_ids[j]);
300 result[frame_id].push_back(model_id);
301 }
302 }
303 return result;
304 } catch (const py::error_already_set& e) {
305 throw Pyston::Exception().log(log4cpp::Priority::ERROR, logger);
306 }
307}
308
311
312 py::object model_fitting = m_measurement_config.attr("model_fitting");
313 py::dict parameters = py::extract<py::dict>(model_fitting.attr("params_dict"));
314 py::list ids = parameters.keys();
315
317 for (int i = 0; i < py::len(ids); ++i) {
318 std::string id = py::extract<std::string>(ids[i]);
319 auto par = parameters[ids[i]];
320 result.emplace(std::make_pair(id, par));
321 }
322 return result;
323}
324
325} // namespace SourceXtractor
#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
static Logging getLogger(const std::string &name="")
void info(const std::string &logMessage)
const Exception & log(log4cpp::Priority::Value level, Elements::Logging &logger) const
static size_t getLockCount()
std::map< int, boost::python::object > getDeVaucouleursModels()
std::map< int, PyAperture > getApertures()
std::map< int, boost::python::object > getMapFromDict(const char *object_name, const char *dict_name)
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()
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)
boost::python::object m_measurement_config
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()
std::map< std::string, boost::python::object > getModelFittingParams()
T make_pair(T... args)
T move(T... args)
static Elements::Logging logger
T system_category(T... args)