cepgen
is hosted by
Hepforge
,
IPPP Durham
CepGen
1.2.5
Central exclusive processes event generator
Loading...
Searching...
No Matches
ObjectPtr.cpp
Go to the documentation of this file.
1
/*
2
* CepGen: a central exclusive processes event generator
3
* Copyright (C) 2018-2024 Laurent Forthomme
4
*
5
* This program is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation, either version 3 of the License, or
8
* any later version.
9
*
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
14
*
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
#include "
CepGen/Core/ParametersList.h
"
20
#include "
CepGen/Utils/Limits.h
"
21
#include "
CepGen/Utils/Message.h
"
22
#include "
CepGen/Utils/String.h
"
23
#include "
CepGenAddOns/PythonWrapper/Error.h
"
24
#include "
CepGenAddOns/PythonWrapper/ObjectPtr.h
"
25
26
using namespace
std::string_literals;
27
28
namespace
cepgen
{
29
namespace
python
{
30
void
obj_deleter
(PyObject* obj) {
31
CG_DEBUG
(
"python:ObjectPtrDeleter"
).log([&obj](
auto
& log) {
32
log <<
"Destroying object at addr 0x"
<< obj <<
" ("
;
33
#if PY_VERSION_HEX >= 0x03110000
34
if
(
auto
* type = Py_TYPE(obj); type)
35
log <<
"type: "
<<
value<std::string>
(PyType_GetName(type)) <<
", "
;
36
#endif
37
log <<
"reference count: "
<< Py_REFCNT(obj) <<
")"
;
38
});
39
Py_DECREF(obj);
40
}
41
42
ObjectPtr::ObjectPtr
(PyObject* obj,
bool
wrap_only)
43
:
PyObjectPtr
(obj, wrap_only ? [](PyObject*) {
/* do not dereference if only wrapping */
} :
obj_deleter
) {}
44
45
ObjectPtr
ObjectPtr::wrap
(PyObject* obj) {
46
ObjectPtr
ptr(obj,
true
);
47
return
ptr;
48
}
49
50
template
<>
51
bool
ObjectPtr::is<int>()
const
{
52
CG_ASSERT
(get());
53
#ifdef PYTHON2
54
return
PyInt_Check(get());
55
#else
56
return
PyLong_Check(get());
57
#endif
58
}
59
60
template
<>
61
bool
ObjectPtr::is<bool>()
const
{
62
CG_ASSERT
(get());
63
return
PyBool_Check(get());
64
}
65
66
template
<>
67
bool
ObjectPtr::is<long>()
const
{
68
CG_ASSERT
(get());
69
#ifdef PYTHON2
70
return
PyInt_Check(get()) || PyLong_Check(get());
71
#else
72
return
PyLong_Check(get());
73
#endif
74
}
75
76
template
<>
77
bool
ObjectPtr::is<double>()
const
{
78
CG_ASSERT
(get());
79
return
PyFloat_Check(get());
80
}
81
82
template
<>
83
bool
ObjectPtr::is<std::string>()
const
{
84
CG_ASSERT
(get());
85
#ifdef PYTHON2
86
return
PyString_Check(get());
87
#else
88
return
PyUnicode_Check(get()) || PyBytes_Check(get());
89
#endif
90
}
91
92
template
<>
93
bool
ObjectPtr::is<Limits>()
const
{
94
if
(!isVector<double>())
95
return
false
;
96
if
(
const
auto
size = vector<double>().size(); size == 1 || size == 2)
97
return
true
;
98
return
false
;
99
}
100
101
template
<>
102
bool
ObjectPtr::is<ParametersList>()
const
{
103
CG_ASSERT
(get());
104
return
PyDict_Check(get());
105
}
106
107
template
<
typename
T>
108
bool
ObjectPtr::isVector
()
const
{
109
CG_ASSERT
(get());
110
const
bool
tuple
= PyTuple_Check(get()), list = PyList_Check(get());
111
if
(!
tuple
&& !list)
// only accept 'tuples' and 'lists'
112
return
false
;
113
if
(
const
auto
size =
tuple
? PyTuple_Size(get()) : list ? PyList_Size(get()) : 0; size == 0)
114
return
true
;
115
const
auto
first =
ObjectPtr::wrap
(
tuple
? PyTuple_GetItem(get(), 0)
/* borrowed */
116
: list ? PyList_GetItem(get(), 0)
/* borrowed */
117
:
nullptr
);
118
if
(!first)
119
return
false
;
120
if
(!first.template is<T>()) {
// only allow same-type tuples/lists
121
CG_DEBUG
(
"python:ObjectPtr:isVector"
)
122
<<
"Wrong object type unpacked from tuple/list: (python)"
<< first->ob_type->tp_name <<
" != (c++)"
123
<<
utils::demangle
(
typeid
(T).name()) <<
"."
;
124
return
false
;
125
}
126
return
true
;
127
}
128
129
template
<
typename
T>
130
std::vector<T>
ObjectPtr::vector
()
const
{
131
if
(!isVector<T>())
132
throw
CG_ERROR
(
"python::ObjectPtr:vector"
)
133
<<
"Object has invalid type: list/tuple != \""
<< get()->ob_type->tp_name <<
"\"."
;
134
std::vector<T> vec;
135
const
bool
tuple
= PyTuple_Check(get());
136
const
Py_ssize_t num_entries =
tuple
? PyTuple_Size(get()) : PyList_Size(get());
137
//--- check every single element inside the list/tuple
138
for
(Py_ssize_t i = 0; i < num_entries; ++i) {
139
auto
pit =
140
ObjectPtr::wrap
(
tuple
? PyTuple_GetItem(get(), i)
/* borrowed */
: PyList_GetItem(get(), i)
/* borrowed */
);
141
if
(!pit.is<T>())
142
throw
CG_ERROR
(
"python::ObjectPtr:vector"
) <<
"Mixed types detected in vector."
;
143
vec.emplace_back(pit.value<T>());
144
}
145
return
vec;
146
}
147
148
template
<>
149
bool
ObjectPtr::value<bool>()
const
{
150
CG_ASSERT
(get());
151
return
PyObject_IsTrue(get());
152
}
153
154
template
<>
155
int
ObjectPtr::value<int>()
const
{
156
if
(!is<int>())
157
throw
CG_ERROR
(
"Python:get"
) <<
"Object has invalid type: integer != \""
<< get()->ob_type->tp_name <<
"\"."
;
158
#ifdef PYTHON2
159
return
PyInt_AsLong(get());
160
#else
161
return
PyLong_AsLong(get());
162
#endif
163
}
164
165
template
<>
166
unsigned
long
ObjectPtr::value<unsigned long>()
const
{
167
if
(!is<long>())
168
throw
CG_ERROR
(
"Python:get"
) <<
"Object has invalid type: unsigned long != \""
<< get()->ob_type->tp_name
169
<<
"\"."
;
170
#ifdef PYTHON2
171
return
PyInt_AsUnsignedLongMask(get());
172
#else
173
return
PyLong_AsUnsignedLong(get());
174
#endif
175
}
176
177
template
<>
178
long
long
ObjectPtr::value<long long>()
const
{
179
if
(!is<long>())
180
throw
CG_ERROR
(
"Python:get"
) <<
"Object has invalid type: long long != \""
<< get()->ob_type->tp_name <<
"\"."
;
181
return
PyLong_AsLongLong(get());
182
}
183
184
template
<>
185
double
ObjectPtr::value<double>()
const
{
186
if
(!is<double>())
187
throw
CG_ERROR
(
"Python:get"
) <<
"Object has invalid type: double != \""
<< get()->ob_type->tp_name <<
"\"."
;
188
return
PyFloat_AsDouble(get());
189
}
190
191
template
<>
192
std::string ObjectPtr::value<std::string>()
const
{
193
if
(!
is<std::string>
())
194
throw
CG_ERROR
(
"Python:get"
) <<
"Object has invalid type: string != \""
<< get()->ob_type->tp_name <<
"\"."
;
195
#ifdef PYTHON2
196
return
PyString_AsString(get());
197
#else
198
if
(PyUnicode_Check(get()))
199
return
PyUnicode_AsUTF8(get());
200
else
// if (PyBytes_Check(get()))
201
return
strdup(PyBytes_AS_STRING(get()));
202
#endif
203
}
204
205
template
<>
206
Limits
ObjectPtr::value<Limits>()
const
{
207
if
(!is<Limits>())
208
throw
CG_ERROR
(
"Python:get"
) <<
"Object has invalid type: limits != \""
<< get()->ob_type->tp_name <<
"\"."
;
209
const
auto
vec = vector<double>();
210
if
(vec.size() == 1)
211
return
Limits
{vec.at(0)};
212
return
Limits
{vec.at(0), vec.at(1)};
213
}
214
215
template
<>
216
ParametersList
ObjectPtr::value<ParametersList>()
const
{
217
if
(!is<ParametersList>())
218
throw
CG_ERROR
(
"Python:get"
) <<
"Object has invalid type: parameters list != \""
<< get()->ob_type->tp_name
219
<<
"\"."
;
220
ParametersList
out;
221
Py_ssize_t pos = 0;
222
PyObject *pkey{
nullptr
}, *pvalue{
nullptr
};
223
while
(PyDict_Next(get(), &pos, &pkey, &pvalue)) {
224
const
auto
key =
ObjectPtr::wrap
(pkey), val =
ObjectPtr::wrap
(pvalue);
225
const
std::string skey = key.is<std::string>() ? key.value<std::string>()
226
: key.is<
int
>() ? std::to_string(key.value<
int
>())
// integer-type key
227
:
"invalid"
;
228
if
(val.is<
bool
>())
229
out.
set
(skey, (
bool
)val.value<
int
>());
230
else
if
(val.is<
int
>())
231
out.
set
(skey, val.value<
int
>());
232
else
if
(val.is<
double
>())
233
out.
set
(skey, val.value<
double
>());
234
else
if
(val.is<std::string>())
235
out.
set
(skey, val.value<std::string>());
236
else
if
(val.is<
ParametersList
>())
237
out.
set
(skey, val.value<
ParametersList
>());
238
else
if
(PyTuple_Check(pvalue) || PyList_Check(pvalue)) {
// vector
239
if
(val.isVector<
int
>())
240
out.
set
(skey, val.vector<
int
>());
241
else
if
(val.isVector<
double
>()) {
242
if
(val.is<
Limits
>())
243
out.
set
(skey, val.value<
Limits
>());
244
out.
set
(skey, val.vector<
double
>());
245
}
else
if
(val.isVector<std::string>())
246
out.
set
(skey, val.vector<std::string>());
247
else
if
(val.isVector<
Limits
>())
248
out.
set
(skey, val.vector<
Limits
>());
249
else
//if (val.isVector<ParametersList>())
250
out.
set
(skey, val.vector<
ParametersList
>());
251
}
else
if
(pvalue == Py_None) {
252
out.
set
(skey,
"None"
s);
253
}
else
{
254
CG_WARNING
(
"PythonTypes"
) <<
"Invalid object ("
<< pvalue->ob_type->tp_name <<
") retrieved for key="
<< skey
255
<<
" when unpacking a dictionary/parameters list."
;
256
}
257
}
258
return
out;
259
}
260
261
template
<>
262
ObjectPtr
ObjectPtr::make<PyObject*>(PyObject*
const
& obj) {
263
return
ObjectPtr
(obj);
264
}
265
266
template
<>
267
ObjectPtr
ObjectPtr::make<int>(
const
int
& val) {
268
#ifdef PYTHON2
269
return
ObjectPtr
(PyInt_FromLong(val));
270
#else
271
return
ObjectPtr
(PyLong_FromLong(val));
272
#endif
273
}
274
275
template
<>
276
ObjectPtr
ObjectPtr::make<bool>(
const
bool
& val) {
277
return
ObjectPtr
(PyBool_FromLong(val));
278
}
279
280
template
<>
281
ObjectPtr
ObjectPtr::make<double>(
const
double
& val) {
282
return
ObjectPtr
(PyFloat_FromDouble(val));
283
}
284
285
template
<>
286
ObjectPtr
ObjectPtr::make<std::string>(
const
std::string& val) {
287
#ifdef PYTHON2
288
return
ObjectPtr
(PyString_FromString(val.c_str()));
289
#else
290
return
ObjectPtr
(PyUnicode_FromString(val.c_str()));
291
#endif
292
}
293
294
template
<>
295
ObjectPtr
ObjectPtr::make<Limits>(
const
Limits
& val) {
296
return
ObjectPtr::tupleFromVector
(std::vector<double>{val.
min
(), val.
max
()});
297
}
298
299
template
<>
300
ObjectPtr
ObjectPtr::make<ParametersList>(
const
ParametersList
& plist) {
301
ObjectPtr
obj(PyDict_New());
302
for
(
const
auto
& key : plist.
keys
(
true
)) {
303
if
(plist.
has
<
bool
>(key))
304
PyDict_SetItem(obj.get(),
make
(key).release(),
make
(plist.
get
<
bool
>(key)).release());
305
else
if
(plist.
has
<
int
>(key))
306
PyDict_SetItem(obj.get(),
make
(key).release(),
make
(plist.
get
<
int
>(key)).release());
307
else
if
(plist.
has
<
double
>(key))
308
PyDict_SetItem(obj.get(),
make
(key).release(),
make
(plist.
get
<
double
>(key)).release());
309
else
if
(plist.
has
<std::string>(key))
310
PyDict_SetItem(obj.get(),
make
(key).release(),
make
(plist.
get
<std::string>(key)).release());
311
else
if
(plist.
has
<
ParametersList
>(key))
312
PyDict_SetItem(obj.get(),
make
(key).release(),
make
(plist.
get
<
ParametersList
>(key)).release());
313
else
if
(plist.
has
<
Limits
>(key)) {
314
const
auto
& lim = plist.
get
<
Limits
>(key);
315
PyDict_SetItem(
316
obj.get(),
make
(key).release(), ObjectPtr::tupleFromVector<double>({lim.min(), lim.max()}).release());
317
}
else
if
(plist.
has
<std::vector<int> >(key))
318
PyDict_SetItem(obj.get(),
319
make
(key).release(),
320
ObjectPtr::tupleFromVector<int>(plist.
get
<std::vector<int> >(key)).release());
321
else
if
(plist.
has
<std::vector<double> >(key))
322
PyDict_SetItem(obj.get(),
323
make
(key).release(),
324
ObjectPtr::tupleFromVector<double>(plist.
get
<std::vector<double> >(key)).release());
325
else
if
(plist.
has
<std::vector<std::string> >(key))
326
PyDict_SetItem(obj.get(),
327
make
(key).release(),
328
ObjectPtr::tupleFromVector<std::string>(plist.
get
<std::vector<std::string> >(key)).release());
329
else
330
throw
PY_ERROR
<<
"Parameters list has an untranslatable object for key="
<< key;
331
}
332
return
obj;
333
}
334
335
template
<
typename
T>
336
ObjectPtr
ObjectPtr::tupleFromVector
(
const
std::vector<T>& vec) {
337
ObjectPtr
tuple
(PyTuple_New(vec.size()));
338
for
(
size_t
i = 0; i < vec.size(); ++i)
339
PyTuple_SetItem(
tuple
.get(), i, make<T>(vec.at(i)).release());
340
return
tuple
;
341
}
342
343
template
<>
344
ObjectPtr
ObjectPtr::tupleFromVector
(
const
std::vector<PyObject*>& vec) {
345
ObjectPtr
tuple
(PyTuple_New(vec.size()));
346
for
(
size_t
i = 0; i < vec.size(); ++i)
347
PyTuple_SetItem(
tuple
.get(), i, vec.at(i));
348
return
tuple
;
349
}
350
351
template
ObjectPtr
ObjectPtr::tupleFromVector<bool>(
const
std::vector<bool>&);
352
template
ObjectPtr
ObjectPtr::tupleFromVector<int>(
const
std::vector<int>&);
353
template
ObjectPtr
ObjectPtr::tupleFromVector<double>(
const
std::vector<double>&);
354
template
ObjectPtr
ObjectPtr::tupleFromVector<std::string>(
const
std::vector<std::string>&);
355
template
ObjectPtr
ObjectPtr::tupleFromVector<Limits>(
const
std::vector<Limits>&);
356
357
std::ostream&
operator<<
(std::ostream& os,
const
ObjectPtr
& ptr) {
358
os <<
"PyObject{"
;
359
if
(
auto
repr
=
ObjectPtr
(PyObject_Str(ptr.get()));
repr
)
// new
360
os <<
repr
.value<std::string>();
361
return
os <<
"}"
;
362
}
363
364
ObjectPtr
ObjectPtr::call
(
const
ObjectPtr
& args)
const
{
365
return
ObjectPtr
(PyObject_CallObject(get(), args.get())
/* new */
);
366
}
367
368
ObjectPtr
ObjectPtr::attribute
(
const
std::string& attr)
const
{
369
if
(PyObject_HasAttrString(get(), attr.c_str()) != 1)
370
return
ObjectPtr
(
nullptr
);
371
return
ObjectPtr
(PyObject_GetAttrString(get(), attr.c_str()));
// new
372
}
373
374
ObjectPtr
ObjectPtr::importModule
(
const
std::string& mod_name) {
375
return
ObjectPtr
(PyImport_Import(ObjectPtr::make<std::string>(mod_name).get()));
// new
376
}
377
378
ObjectPtr
ObjectPtr::defineModule
(
const
std::string& mod_name,
const
std::string& code) {
379
auto
mod =
ObjectPtr
(PyImport_AddModule(mod_name.data()));
380
if
(!mod)
381
throw
PY_ERROR
<<
"Failed to add the module."
;
382
auto
* local_dict = PyModule_GetDict(mod.get());
383
if
(!local_dict)
384
throw
PY_ERROR
<<
"Failed to retrieve the local dictionary from module."
;
385
ObjectPtr::wrap
(PyRun_String(code.data(), Py_file_input, local_dict, local_dict));
386
CG_DEBUG
(
"Python:defineModule"
) <<
"New '"
<< mod_name <<
"' module initialised from Python code parsing.\n"
387
<<
"List of attributes: "
388
<<
ObjectPtr
(PyObject_Dir(mod.get())).
vector
<std::string>() <<
"."
;
389
return
mod;
390
}
391
}
// namespace python
392
}
// namespace cepgen
Error.h
PY_ERROR
#define PY_ERROR
Definition
Error.h:25
CG_ERROR
#define CG_ERROR(mod)
Definition
Exception.h:60
CG_ASSERT
#define CG_ASSERT(assertion)
Definition
Exception.h:62
Limits.h
Message.h
CG_WARNING
#define CG_WARNING(mod)
Definition
Message.h:228
CG_DEBUG
#define CG_DEBUG(mod)
Definition
Message.h:220
ObjectPtr.h
ParametersList.h
String.h
cepgen::Limits
Validity interval for a variable.
Definition
Limits.h:28
cepgen::Limits::min
double min() const
Lower limit to apply on the variable.
Definition
Limits.h:52
cepgen::Limits::max
double max() const
Upper limit to apply on the variable.
Definition
Limits.h:54
cepgen::ParametersList
Definition
ParametersList.h:52
cepgen::ParametersList::has
bool has(const std::string &key) const
Check if a given parameter is handled in this list.
Definition
ParametersList.cpp:386
cepgen::ParametersList::keys
std::vector< std::string > keys(bool name_key=true) const
Definition
ParametersList.cpp:298
cepgen::ParametersList::get
T get(const std::string &key, const T &def=default_arg< T >::get()) const
Get a parameter value.
Definition
ParametersList.cpp:391
cepgen::ParametersList::set
ParametersList & set(const std::string &, const T &)
Set a parameter value Set a recast parameter value.
Definition
ParametersList.cpp:401
cepgen::python::ObjectPtr
Smart pointer to a Python object and its dereferencing operator.
Definition
ObjectPtr.h:36
cepgen::python::ObjectPtr::isVector
bool isVector() const
Check if a Python object is compatible with a vector of uniform objects.
Definition
ObjectPtr.cpp:108
cepgen::python::ObjectPtr::attribute
ObjectPtr attribute(const std::string &) const
Retrieve the attribute from a python object.
Definition
ObjectPtr.cpp:368
cepgen::python::ObjectPtr::vector
std::vector< T > vector() const
Retrieve a vector of objects, either from a Python list or tuple.
Definition
ObjectPtr.cpp:130
cepgen::python::ObjectPtr::importModule
static ObjectPtr importModule(const std::string &)
Import a Python module in a new reference-counted Python object.
Definition
ObjectPtr.cpp:374
cepgen::python::ObjectPtr::wrap
static ObjectPtr wrap(PyObject *)
Wrap a PyObject without cleaning at the destructor.
Definition
ObjectPtr.cpp:45
cepgen::python::ObjectPtr::defineModule
static ObjectPtr defineModule(const std::string &, const std::string &)
Define a Python module from a Python code in a new reference-counted Python object.
Definition
ObjectPtr.cpp:378
cepgen::python::ObjectPtr::tuple
static ObjectPtr tuple(const std::tuple< Args... > &c_tuple)
Build a Python tuple from a C++ tuple.
Definition
ObjectPtr.h:77
cepgen::python::ObjectPtr::ObjectPtr
ObjectPtr(PyObject *, bool wrap_only=false)
Definition
ObjectPtr.cpp:42
cepgen::python::ObjectPtr::make
static ObjectPtr make(const T &)
Build a new Python object from a C++ one.
cepgen::python::ObjectPtr::call
ObjectPtr call(const ObjectPtr &) const
Call a python function with a tuple of arguments.
Definition
ObjectPtr.cpp:364
cepgen::python::ObjectPtr::tupleFromVector
static ObjectPtr tupleFromVector(const std::vector< T > &)
Build a Python tuple from a (uniform) vector of objects.
Definition
ObjectPtr.cpp:336
cepgen::python::is< std::string >
bool ObjectPtr::is< std::string >() const
Definition
ObjectPtr.cpp:83
cepgen::python::PyObjectPtr
std::unique_ptr< PyObject, void(*)(PyObject *)> PyObjectPtr
Definition
ObjectPtr.h:34
cepgen::python::operator<<
std::ostream & operator<<(std::ostream &os, const ObjectPtr &ptr)
Definition
ObjectPtr.cpp:357
cepgen::python::value< std::string >
std::string ObjectPtr::value< std::string >() const
Definition
ObjectPtr.cpp:192
cepgen::python::obj_deleter
void obj_deleter(PyObject *obj)
Definition
ObjectPtr.cpp:30
cepgen::python::repr
static std::string repr(const ParametersList ¶ms, const std::string &key)
Definition
ConfigWriter.cpp:34
cepgen::utils::demangle
std::string demangle(const char *name)
Demangle a type id if possible.
Definition
String.cpp:341
cepgen
Common namespace for this Monte Carlo generator.
Definition
CommandLineHandler.cpp:36
python
Definition
__init__.py:1
CepGenAddOns
PythonWrapper
ObjectPtr.cpp
Generated on Mon Jul 29 2024 for CepGen by
1.9.7