ATLAS Offline Software
pythonic_coracool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 // Efficient pythonic CoraCool bindings
6 // Author: <peter.waller@cern.ch> Jan 2010
7 
8 #define likely(x) __builtin_expect((x),1)
9 #define unlikely(x) __builtin_expect((x),0)
10 
11 #include <Python.h>
12 
13 #include <CoolKernel/ChannelSelection.h>
14 #include <CoolKernel/IFolder.h>
15 #include <CoolKernel/IDatabase.h>
16 
17 #include "CoralBase/Attribute.h"
18 #include "CoralBase/AttributeList.h"
19 #include "CoralBase/AttributeListSpecification.h"
20 
27 
28 #include <boost/bind/bind.hpp>
29 #include <boost/function.hpp>
30 
31 #include <string>
32 #include <iostream>
33 
36 
37 using std::cout;
38 using std::endl;
39 using std::string;
40 using std::vector;
41 
42 using boost::bind;
43 using boost::placeholders::_1;
44 using cool::IFolderPtr;
45 using cool::IDatabasePtr;
46 using cool::ChannelSelection;
47 using cool::ValidityKey;
48 using coral::Attribute;
49 using coral::AttributeSpecification;
51 
52 typedef boost::function<PyObject* (const AttributeList&)>
54 
55 // A function to signal that a conversion object could not be found
57 
58 // Re-use these two functions from quick_retrieve.cxx
60 PyObject *qr_PyString_FromStdString(const string& str);
61 
62 template<typename T>
63 const T& fetch_attribute_data(const coral::Attribute& A)
64 {
65  return A.data<T>();
66 }
67 
68 // Returns a functor which returns a Python object for the attribute with
69 // a given name and type. Test type_name against a series of fetchers.
70 // If none are found, no_coral_conversion_available is returned.
72  const string& type_name)
73 {
74  // Force the type of fetch_attribute, bind cannot infer it unfortunately.
75  const Attribute& (AttributeList::*fetch_attribute)(const string) const =
76  &AttributeList::operator[];
77 
78  // below, _1 falls through to leave you with a function that "looks like"
79  // [converter(attr[name].data<type>())] (Attribute& attr)
80 
81  // Test type against type_name. If true, return a functor for this type.
82  #define MAKE_FETCHER(type, converter) \
83  if (type_name == #type) \
84  return bind(converter, \
85  bind(fetch_attribute_data<type>, \
86  bind(fetch_attribute, _1, name) \
87  ) \
88  );
89 
90  // See the python c-api reference for python conversion functions
91  // Python/C API Reference Manual >> Concrete Objects Layer
92  // http://docs.python.org/c-api/concrete.html
93 
94  MAKE_FETCHER(short, PyLong_FromLong)
95  MAKE_FETCHER(int, PyLong_FromLong)
96  MAKE_FETCHER(long long, PyLong_FromLongLong)
97 
98  /*
99 
100  Types from COOL:
101  We need to build up a similar list from CORAL, it would be nice to know
102  where they came from.
103 
104  MAKE_FETCHER(Bool, PyBool_FromLong)
105  MAKE_FETCHER(Float, PyFloat_FromDouble)
106  MAKE_FETCHER(Double, PyFloat_FromDouble)
107  MAKE_FETCHER(UChar, PyLong_FromLong)
108  MAKE_FETCHER(UInt16, PyLong_FromUnsignedLong)
109  MAKE_FETCHER(UInt32, PyLong_FromUnsignedLong)
110  MAKE_FETCHER(UInt63, PyLong_FromUnsignedLongLong)
111  MAKE_FETCHER(UInt64, PyLong_FromUnsignedLongLong)
112  MAKE_FETCHER(String255, qr_PyString_FromStdString)
113  MAKE_FETCHER(String4k, qr_PyString_FromStdString)
114  MAKE_FETCHER(String64k, qr_PyString_FromStdString)
115  MAKE_FETCHER(String16M, qr_PyString_FromStdString)
116  MAKE_FETCHER(Blob16M, qr_PyString_FromBlob)
117  MAKE_FETCHER(Blob64k, qr_PyString_FromBlob)
118  */
119 
120  PyErr_Format(PyExc_RuntimeError,
121  "Type '%s' is not in type conversion table. "
122  "Please add it to pythonic_coracool.cxx. "
123  "Can't convert field '%s'.",
124  type_name.c_str(),
125  name);
127 }
128 
129 // From a list of python strings (to_fetch) (which are attribute names)
130 // Create a fetcher for each attribute, and insert them into the
131 // payload_fetchers vector
133  PyObject *to_fetch,
134  const AttributeList& attribute_list,
135  vector<coral_attribute_fetcher_t>& payload_fetchers)
136 {
137  const Py_ssize_t count = to_fetch ? PySequence_Size(to_fetch) : 0;
138 
139  for (Py_ssize_t i = 0; i < count; i++)
140  {
141  PyObject *py_name = PySequence_GetItem(to_fetch, i);
142 #if PY_VERSION_HEX < 0x03000000
143  const char *name = PyString_AsString(py_name);
144 #else
145  const char *name = _PyUnicode_AsString(py_name);
146 #endif
147  const string type = attribute_list[name].specification().typeName();
148 
150 
152  return false; // Failure: A python exception was thrown above
153 
154  payload_fetchers.push_back(pf);
155  Py_DECREF(py_name);
156  }
157 
158  return true; // Success
159 }
160 
161 inline PyObject *apply_function(PyObject *function, PyObject *object)
162 {
163  // Convert object according to function, taking care of references
164  // If function is null, return unmodified object
165  if (!function || function == Py_None) return object;
166  PyObject *old_object = object;
167  PyObject *new_object = PyObject_CallObject(function, object);
168  Py_DECREF(old_object);
169  return new_object;
170 }
171 
172 CoraCoolFolderPtr fetch_coracool_folder(IDatabasePtr cooldb, const string & folder)
173 {
174  CoraCoolDatabaseSvc& corasvc = CoraCoolDatabaseSvcFactory::
175  databaseService();
176 
177  CoraCoolDatabasePtr coradb = corasvc.openDatabase(
178  cooldb->databaseId(), cooldb, true);
179 
180  return coradb->getFolder(folder.c_str());
181 }
182 
183 const cool::RecordSpecification
184  get_coracool_payload_spec(IDatabasePtr cooldb, const string & folder)
185 {
186  return fetch_coracool_folder(cooldb, folder)->payloadSpecification();
187 }
188 
189 inline PyObject* make_iov_key(PyObject *iovkey_wrapper,
190  unsigned long long value)
191 {
192  static const char * const argtypes = const_cast<char *>("K");
193  if (iovkey_wrapper && iovkey_wrapper != Py_None)
194  return PyObject_CallFunction(iovkey_wrapper, argtypes, value);
195  return PyLong_FromUnsignedLongLong(value);
196 }
197 
198 PyObject *browse_coracool(IDatabasePtr cooldb, const string & folder,
199  ValidityKey since, ValidityKey until,
200  const ChannelSelection &cs = ChannelSelection::all(),
201  const char *tag="",
202  PyObject *to_fetch = NULL,
203  PyObject *object_converter = NULL,
204  PyObject *inner_object_converter = NULL,
205  PyObject *iovkey_wrapper = NULL)
206 {
207  // Browse CoraCool objects
208  CoraCoolFolderPtr coralFolder = fetch_coracool_folder(cooldb, folder);
209  CoraCoolObjectIterPtr objects = coralFolder->browseObjects(since, until,
210  cs, tag);
211 
212  // Number of attributes to be fetched
213  const Py_ssize_t count = to_fetch ? PySequence_Size(to_fetch) : 0;
214 
215  PyObject* result = PyList_New(0); // List which is returned by this function
216  bool first = true; // Is this the first iteration?
217  CoraCoolObject::const_iterator payload; // Current payload
218 
219  // List of functors which convert an Attribute into a python value
220  vector<coral_attribute_fetcher_t> payload_fetchers;
221 
222  // Loop over IoVs
223  while (objects->hasNext())
224  {
225  const CoraCoolObjectPtr& object = objects->next();
226 
227  PyObject *py_payload_tuple = PyTuple_New(object->size());
228  unsigned int payload_index = 0;
229 
230  // Loop over multiple payloads per record
231  for (payload = object->begin();
232  payload != object->end();
233  ++payload, ++payload_index)
234  {
235  if (unlikely(first))
236  {
237  // On the first iteration, figure out the types and create
238  // specialised functions for retrieving them
239  first = false;
240  if (!make_fetchers(to_fetch, *payload, payload_fetchers))
241  return NULL; // Failure, throw python exception from above
242  }
243 
244  // Create a tuple for the payload and fill it from payload fetchers
245  PyObject *py_payload = PyTuple_New(count);
246  for (Py_ssize_t i = 0; i < count; i++)
247  PyTuple_SET_ITEM(py_payload, i, payload_fetchers[i](*payload));
248 
249  py_payload = apply_function(inner_object_converter, py_payload);
250 
251  if (!py_payload)
252  {
253  // apply_function returned an error
254  // We won't return the list to python so we need to tell python it
255  // can be deleted
256  Py_DECREF(py_payload_tuple);
257  Py_DECREF(result);
258  return NULL;
259  }
260 
261  PyTuple_SET_ITEM(py_payload_tuple, payload_index, py_payload);
262  }
263 
264  PyObject *one = PyTuple_New(4);
265 
266  PyTuple_SET_ITEM(one, 0, make_iov_key(iovkey_wrapper, object->since()));
267  PyTuple_SET_ITEM(one, 1, make_iov_key(iovkey_wrapper, object->until()));
268 
269  PyTuple_SET_ITEM(one, 2, PyLong_FromLong(object->channelId()));
270 
271  // SET_ITEM steals reference, no decref needed
272  PyTuple_SET_ITEM(one, 3, py_payload_tuple);
273 
274  one = apply_function(object_converter, one);
275  if (!one)
276  {
277  // apply_function returned an error
278  // We won't return the list to python so we need to tell python it
279  // can be deleted
280  Py_DECREF(result);
281  return NULL;
282  }
283 
284  PyList_Append(result, one);
285  Py_DECREF(one);
286  }
287 
288  return result;
289 }
get_generator_info.result
result
Definition: get_generator_info.py:21
make_fetchers
bool make_fetchers(PyObject *to_fetch, const AttributeList &attribute_list, vector< coral_attribute_fetcher_t > &payload_fetchers)
Definition: pythonic_coracool.cxx:132
LArConditions2Ntuple.objects
objects
Definition: LArConditions2Ntuple.py:56
CoraCoolDatabaseSvc.h
create_attribute_fetcher
coral_attribute_fetcher_t create_attribute_fetcher(const char *name, const string &type_name)
Definition: pythonic_coracool.cxx:71
Trk::one
@ one
Definition: TrkDetDescr/TrkSurfaces/TrkSurfaces/RealQuadraticEquation.h:22
python.subdetectors.tile.Blob
Blob
Definition: tile.py:17
athena.value
value
Definition: athena.py:122
CoraCoolDatabaseSvc
Definition: CoraCoolDatabaseSvc.h:25
python.PyKernel.AttributeList
AttributeList
Definition: PyKernel.py:36
XMLtoHeader.count
count
Definition: XMLtoHeader.py:85
CoraCoolObject.h
python.AthDsoLogger.argtypes
argtypes
Definition: AthDsoLogger.py:44
dq_defect_copy_defect_database.since
def since
Definition: dq_defect_copy_defect_database.py:54
dqt_zlumi_alleff_HIST.A
A
Definition: dqt_zlumi_alleff_HIST.py:110
dq_defect_copy_defect_database.until
def until
Definition: dq_defect_copy_defect_database.py:55
CoraCoolObject::const_iterator
AttrListVec::const_iterator const_iterator
Definition: CoraCoolObject.h:23
lumiFormat.i
int i
Definition: lumiFormat.py:92
get_coracool_payload_spec
const cool::RecordSpecification get_coracool_payload_spec(IDatabasePtr cooldb, const string &folder)
Definition: pythonic_coracool.cxx:184
unlikely
#define unlikely(x)
Definition: pythonic_coracool.cxx:9
apply_function
PyObject * apply_function(PyObject *function, PyObject *object)
Definition: pythonic_coracool.cxx:161
make_iov_key
PyObject * make_iov_key(PyObject *iovkey_wrapper, unsigned long long value)
Definition: pythonic_coracool.cxx:189
CoraCoolFolderPtr
boost::shared_ptr< CoraCoolFolder > CoraCoolFolderPtr
Definition: CoraCoolTypes.h:15
fetch_coracool_folder
CoraCoolFolderPtr fetch_coracool_folder(IDatabasePtr cooldb, const string &folder)
Definition: pythonic_coracool.cxx:172
CoraCoolDatabasePtr
boost::shared_ptr< CoraCoolDatabase > CoraCoolDatabasePtr
Definition: CoraCoolTypes.h:12
CoraCoolFolder.h
CoraCoolDatabaseSvc::openDatabase
CoraCoolDatabasePtr openDatabase(const std::string &dbconn, cool::IDatabasePtr cooldb, bool readonly=false)
Definition: CoraCoolDatabaseSvc.cxx:23
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:192
PixelModuleFeMask_create_db.payload
string payload
Definition: PixelModuleFeMask_create_db.py:69
Cut::all
@ all
Definition: SUSYToolsAlg.cxx:64
ATLAS_NO_CHECK_FILE_THREAD_SAFETY
ATLAS_NO_CHECK_FILE_THREAD_SAFETY
Definition: pythonic_coracool.cxx:35
MAKE_FETCHER
#define MAKE_FETCHER(type, converter)
CoraCoolObjectIterPtr
boost::shared_ptr< CoraCoolObjectIter > CoraCoolObjectIterPtr
Definition: CoraCoolTypes.h:21
python.output.AtlRunQueryRoot.pf
pf
Definition: AtlRunQueryRoot.py:988
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
DeMoScan.first
bool first
Definition: DeMoScan.py:534
CoraCoolObjectPtr
boost::shared_ptr< CoraCoolObject > CoraCoolObjectPtr
Definition: CoraCoolTypes.h:18
qr_PyString_FromStdString
PyObject * qr_PyString_FromStdString(const string &str)
Definition: quick_retrieve.cxx:118
qr_PyString_FromBlob
PyObject * qr_PyString_FromBlob(const coral::Blob &blob)
Definition: quick_retrieve.cxx:108
CoraCoolDatabase.h
CaloCondBlobAlgs_fillNoiseFromASCII.folder
folder
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:56
fetch_attribute_data
const T & fetch_attribute_data(const coral::Attribute &A)
Definition: pythonic_coracool.cxx:63
CoraCoolObjectIter.h
pickleTool.object
object
Definition: pickleTool.py:30
str
Definition: BTagTrackIpAccessor.cxx:11
CaloCondBlobAlgs_fillNoiseFromASCII.tag
string tag
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:24
CoraCoolDatabaseSvcFactory.h
checker_macros.h
Define macros for attributes used to control the static checker.
browse_coracool
PyObject * browse_coracool(IDatabasePtr cooldb, const string &folder, ValidityKey since, ValidityKey until, const ChannelSelection &cs=ChannelSelection::all(), const char *tag="", PyObject *to_fetch=NULL, PyObject *object_converter=NULL, PyObject *inner_object_converter=NULL, PyObject *iovkey_wrapper=NULL)
Definition: pythonic_coracool.cxx:198
PyObject
_object PyObject
Definition: IPyComponent.h:26
no_coral_conversion_available
PyObject * no_coral_conversion_available(const AttributeList &)
Definition: pythonic_coracool.cxx:56
TSU::T
unsigned long long T
Definition: L1TopoDataTypes.h:35
CaloCondBlobAlgs_fillNoiseFromASCII.blob
blob
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:96
coral_attribute_fetcher_t
boost::function< PyObject *(const AttributeList &)> coral_attribute_fetcher_t
Definition: pythonic_coracool.cxx:53