ATLAS Offline Software
CreateClassesForFolder.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 # Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
4 
5 __doc__ = """
6 CreateClassesForFolder.py
7 
8 Python script that creates C++ .h/.cxx files that contain the container and object class
9 representing the structure of a database folder.
10 """
11 
12 import argparse
13 import os.path
14 import string
15 import sys
16 import uuid
17 
18 from CLIDComps.clidGenerator import clidGenerator
19 from PyCool import cool,coral
20 
21 _dbSvc = cool.DatabaseSvcFactory.databaseService()
22 _cliddb = clidGenerator("")
23 
24 _container_header = """// -*- C++ -*-
25 #ifndef TRIGT1CALOCALIBCONDITIONS_${CONTAINERNAME}_H
26 #define TRIGT1CALOCALIBCONDITIONS_${CONTAINERNAME}_H
27 
28 #include <map>
29 #include <string>
30 #include <vector>
31 #include "AthenaKernel/CLASS_DEF.h"
32 #include "GaudiKernel/DataObject.h"
33 #include "TrigT1CaloCalibConditions/AbstractL1CaloPersistentCondition.h"
34 #include "TrigT1CaloCalibConditions/L1CaloCoolChannelId.h"
35 
36 class CondAttrListCollection;
37 class ${ObjectName};
38 
39 /***
40 * Container of ${ObjectName} objects. Automatically created using:
41 *
42 * ${CommandLine}
43 */
44 class ${ContainerName} : public DataObject, virtual public AbstractL1CaloPersistentCondition
45 {
46 private:
47  enum eAttrSpecification { ${EnumAttrSpecification} };
48 public:
49  ${ContainerName}();
50  ${ContainerName}(const std::string& folderKey);
51  virtual ~${ContainerName}() {}
52 
53  // interface of AbstractL1CaloPersistentCondition
54  using AbstractL1CaloPersistentCondition::makeTransient;
55  virtual void makeTransient(const std::map<std::string, const CondAttrListCollection*>);
56  virtual DataObject* makePersistent() const;
57  virtual std::vector<std::string> coolInputKeys() const { return {m_coolFolderKey}; }
58  virtual std::string coolOutputKey() const { return m_coolFolderKey; }
59  virtual void clear() { m_${folderName}s.clear(); }
60 
61  // getters
62  const ${ObjectName}* ${folderName}(unsigned int channelId) const;
63  const ${ObjectName}* ${folderName}(const L1CaloCoolChannelId& channelId) const {
64  return ${folderName}(channelId.id());
65  }
66 
67  using const_iterator = std::vector<${ObjectName}>::const_iterator;
68  const_iterator begin() const { return m_${folderName}s.begin(); }
69  const_iterator end() const { return m_${folderName}s.end(); }
70 
71  // setters
72  void add${FolderName}(const ${ObjectName}& ${folderName});
73 
74 private:
75  std::vector<${ObjectName}> m_${folderName}s;
76  std::string m_coolFolderKey = "${FullFolderPath}";
77 };
78 
79 ${ClassDefMacro}
80 
81 #endif // TRIGT1CALOCALIBCONDITIONS_${CONTAINERNAME}_H
82 """
83 
84 _container_src = """#include "TrigT1CaloCalibConditions/${ContainerName}.h"
85 
86 #include <algorithm>
87 #include <memory>
88 
89 #include "CoralBase/AttributeListSpecification.h"
90 #include "AthenaPoolUtilities/CondAttrListCollection.h"
91 #include "AthenaPoolUtilities/AthenaAttributeList.h"
92 
93 #include "TrigT1CaloCalibConditions/${ObjectName}.h"
94 
95 ${ContainerName}::${ContainerName}()
96  : AbstractL1CaloPersistentCondition("CondAttrListCollection")
97 {
98 ${DefineSpecificationList}
99 }
100 
101 ${ContainerName}::${ContainerName}(const std::string& folderKey)
102  : ${ContainerName}() // delegating constructor
103 {
104  m_coolFolderKey = folderKey;
105 }
106 
107 
108 DataObject* ${ContainerName}::makePersistent() const
109 {
110  using std::make_unique;
111 
112  if(m_coolFolderKey.empty()) return nullptr;
113 
114  auto* attrSpecification = this->createAttributeListSpecification();
115  if(!attrSpecification || !attrSpecification->size()) return nullptr;
116 
117  auto attrListCollection = make_unique<CondAttrListCollection>(true);
118  for(const auto& item : m_${folderName}s) {
119  AthenaAttributeList attrList(*attrSpecification);
120 ${AddSpecificationList}
121 
122  attrListCollection->add(item.channelId(), attrList);
123  }
124  return static_cast<DataObject*>(attrListCollection.release());
125 }
126 
127 void ${ContainerName}::makeTransient(const std::map<std::string, const CondAttrListCollection*> condAttrListCollectionMap)
128 {
129  clear();
130 
131  auto it = condAttrListCollectionMap.find(m_coolFolderKey);
132  if(it == std::end(condAttrListCollectionMap)) return;
133 
134  auto attrListCollection = it->second;
135  for(const auto& item : *attrListCollection) {
136  auto chanNum = item.first;
137  const auto& attrList = item.second;
138 
139 ${ReadSpecificationList}
140 
141  add${FolderName}(${ObjectName}(chanNum, ${AttrList}));
142  }
143 }
144 
145 const ${ObjectName}* ${ContainerName}::${folderName}(unsigned int channelId) const
146 {
147  auto it = std::lower_bound(std::begin(m_${folderName}s),
148  std::end(m_${folderName}s),
149  channelId,
150  [](const ${ObjectName}& el, unsigned int val) -> bool {
151  return el.channelId() < val;
152  });
153  if(it == std::end(m_${folderName}s)) return nullptr;
154  return &(*it);
155 }
156 
157 void ${ContainerName}::add${FolderName}(const ${ObjectName}& ${folderName})
158 {
159  // insert into the correct position mainting the sorted vector
160  m_${folderName}s.insert(std::lower_bound(std::begin(m_${folderName}s),
161  std::end(m_${folderName}s),
162  ${folderName}.channelId(),
163  [](const ${ObjectName}& el, unsigned int va) -> bool {
164  return el.channelId() < va;
165  }),
166  ${folderName});
167 }
168 """
169 
170 _object_header = """// -*- C++ -*-
171 #ifndef TRIGT1CALOCALIBCONDITIONS_${OBJECTNAME}_H
172 #define TRIGT1CALOCALIBCONDITIONS_${OBJECTNAME}_H
173 
174 /**
175  * Folder <-> Object mapping for ${FullFolderPath} .
176  * Automatically created using:
177  *
178  * ${CommandLine}
179  */
180 class ${ObjectName}
181 {
182 public:
183  ${ObjectName}() {}
184  ${ObjectName}(unsigned int channelId, ${AttrTypeNameList});
185 
186  unsigned int channelId() const { return m_channelId; }
187 ${GetterList}
188 
189  void setChannelId(unsigned int channelId) { m_channelId = channelId; }
190 ${SetterList}
191 
192 private:
193  unsigned int m_channelId = 0;
194 ${AttrDefinitions}
195 };
196 
197 #endif // TRIGT1CALOCALIBCONDITIONS_${OBJECTNAME}_H
198 """
199 
200 _object_src = """#include "TrigT1CaloCalibConditions/${ObjectName}.h"
201 
202 ${ObjectName}::${ObjectName}(unsigned int channelId, ${AttrTypeNameList})
203  : m_channelId(channelId)
204 ${AttrConstructorList}
205 {
206 }
207 """
208 
209 def add_args(parser):
210  """ Add arguments to the ArgumentParser @parser. """
211  parser.add_argument('folder', help='Folder which the class should represent')
212  parser.add_argument('--include', help='Comma separated list of attributes to include')
213  parser.add_argument('--exclude', help='Comma separated list of attributes to exclude')
214  parser.add_argument('--objectName', help='Name of object class')
215  parser.add_argument('--containerName', help='Name of container class')
216  parser.add_argument('--db', help='Connection string of the database',
217  default='COOLONL_TRIGGER/CONDBR2')
218 
219 def _mapToCpp(t):
220  _m = {
221  'UInt16': 'unsigned short',
222  'UInt32': 'unsigned int',
223  'UInt63': 'unsigned long long',
224  'Int16' : 'short',
225  'Int32' : 'int',
226  'Double': 'double',
227  'Blob64k': 'char*',
228  'String255': 'char*'
229  }
230  return _m[t]
231 
232 def _toCamelCase(identifier):
233  return '{0}{1}'.format(identifier[0].lower(), identifier[1:])
234 
236  _l = ' attrList[specificationName(e{AttrName})].setValue(item.{attrName}());'
237  result = []
238  for name in nameList:
239  result.append(_l.format(AttrName=name, attrName=_toCamelCase(name)))
240  return '\n'.join(result)
241 
243  _l = ' this->addSpecification(e{AttrName}, "{AttrName}", "{attrType}");'
244  result = []
245  for (n, t) in nameTypeList:
246  result.append(_l.format(AttrName=n, attrType=_mapToCpp(t)))
247  return '\n'.join(result)
248 
250  _l = ' auto {attrName} = attrList[specificationName(e{AttrName})].data<{attrType}>();'
251  result = []
252  for (n, t) in nameTypeList:
253  result.append(_l.format(AttrName=n, attrName=_toCamelCase(n), attrType=_mapToCpp(t)))
254  return '\n'.join(result)
255 
256 def _createGetterList(nameTypeList):
257  _l = ' {attrType} {attrName}() const {{ return m_{attrName}; }}'
258  result = []
259  for (n, t) in nameTypeList:
260  result.append(_l.format(attrName=_toCamelCase(n), attrType=_mapToCpp(t)))
261  return '\n'.join(result)
262 
263 def _createSetterList(nameTypeList):
264  _l = ' void set{AttrName}({attrType} {attrName}) {{ m_{attrName} = {attrName}; }}'
265  result = []
266  for (n, t) in nameTypeList:
267  result.append(_l.format(AttrName=n, attrName=_toCamelCase(n), attrType=_mapToCpp(t)))
268  return '\n'.join(result)
269 
270 def _createAttrDefinitions(nameTypeList):
271  _l = ' {attrType} m_{attrName} = 0;'
272  result = []
273  for (n, t) in nameTypeList:
274  result.append(_l.format(attrName=_toCamelCase(n), attrType=_mapToCpp(t)))
275  return '\n'.join(result)
276 
278  _l = ' , m_{attrName}({attrName})'
279  result = []
280  for n in nameList:
281  result.append(_l.format(attrName=_toCamelCase(n)))
282  return '\n'.join(result)
283 
284 def _writeToFile(fname, template, mapping):
285  f = open(fname, 'w')
286  f.write(string.Template(template).substitute(mapping))
287  f.close()
288 
289 def create_classes_from_folder(folder, attrExcludeList, attrIncludeList, containerName, objectName):
290  """ Does the actual work ... """
291  folderName = folder.fullPath().split('/')[-1]
292  attrNames = [ps.name() for ps in folder.payloadSpecification()]
293  if attrIncludeList:
294  attrNames = filter(lambda n: n in attrIncludeList, attrNames)
295  elif attrExcludeList:
296  attrNames = filter(lambda n: n not in attrExcludeList, attrNames)
297 
298  attrTypes = [ps.storageType().name() for ps in folder.payloadSpecification() \
299  if ps.name() in attrNames]
300  attrNameTypes = zip(attrNames, attrTypes)
301 
302  if not containerName:
303  containerName = 'L1Calo{0}Container'.format(folderName)
304  if not objectName:
305  objectName = 'L1Calo{0}'.format(folderName)
306 
307  # prepare the replacements for the container class
308  mapping = {}
309  mapping['CommandLine'] = ' '.join(sys.argv)
310  mapping['ContainerName'] = containerName
311  mapping['CONTAINERNAME'] = containerName.upper()
312  mapping['FolderName'] = folderName
313  mapping['folderName'] = _toCamelCase(folderName)
314  mapping['ObjectName'] = objectName
315  mapping['EnumAttrSpecification'] = ', '.join(['e{0}'.format(n) for n in attrNames])
316  mapping['FullFolderPath'] = folder.fullPath()
317  mapping['ClassDefMacro'] = \
318  'CLASS_DEF( {0}, {1}, 1 )'.format(containerName,
319  _cliddb.genClidFromName(containerName))
320 
321  mapping['DefineSpecificationList'] = _createDefineSpecificationList(attrNameTypes)
322  mapping['AddSpecificationList'] = _createAddSpecificationList(attrNames)
323  mapping['ReadSpecificationList'] = _createReadSpecificationList(attrNameTypes)
324  mapping['AttrList'] = ', '.join(map(_toCamelCase, attrNames))
325 
326  # write the files
327  _writeToFile('{0}.h'.format(containerName), _container_header, mapping)
328  _writeToFile('{0}.cxx'.format(containerName), _container_src, mapping)
329 
330  # prepare the replacements for the object class
331  for not_needed in ('ContainerName', 'CONTAINERNAME', 'FolderName', 'folderName',
332  'EnumAttrSpecification', 'ClassDefMacro', 'DefineSpecificationList',
333  'AddSpecificationList', 'ReadSpecificationList', 'AttrList'):
334  del mapping[not_needed]
335  mapping['OBJECTNAME'] = objectName.upper()
336  mapping['AttrTypeNameList'] = ', '.join(['{0} {1}'.format(_mapToCpp(t), _toCamelCase(n)) for (n,t) in attrNameTypes])
337  mapping['GetterList'] = _createGetterList(attrNameTypes)
338  mapping['SetterList'] = _createSetterList(attrNameTypes)
339  mapping['AttrDefinitions'] = _createAttrDefinitions(attrNameTypes)
340  mapping['AttrConstructorList'] = _createAttrConstructorList(attrNames)
341 
342  # write the files
343  _writeToFile('{0}.h'.format(objectName), _object_header, mapping)
344  _writeToFile('{0}.cxx'.format(objectName), _object_src, mapping)
345 
346  # redefine mapping for slection.xml / *PACKAGE*Dict.h
347  mapping = {
348  'cont' : containerName,
349  'obj' : objectName,
350  'id' : str(uuid.uuid4()).upper()
351  }
352  print
353  print '[I] Add the following to the selection.xml file:'
354  print ' <class name="{cont}" id="{id}" />'.format(**mapping)
355  print ' <class name="{cont}::const_iterator" />'.format(**mapping)
356  print ' <class name="{obj}" />'.format(**mapping)
357  print
358  print '[I] Add the following to the TrigT1CaloCalibConditionsDict.h file:'
359  print '#include "TrigT1CaloCalibConditions/{cont}.h"'.format(**mapping)
360  print '#include "TrigT1CaloCalibConditions/{obj}.h"'.format(**mapping)
361  print
362  print ' {cont}::const_iterator {cont}ConstInterator;'.format(**mapping)
363 
364 def main():
365  """ Entry point """
366  parser = argparse.ArgumentParser(description='Create C++ classes that represent COOL database folders')
367  add_args(parser)
368  args = parser.parse_args()
369 
370  if args.include and args.exclude:
371  raise RuntimeError("Options --include and --exclude are mutually exclusive.")
372 
373  db = _dbSvc.openDatabase(args.db)
374  folder = db.getFolder(args.folder)
375 
377  args.exclude.split(',') if args.exclude else None,
378  args.include.split(',') if args.include else None,
379  args.containerName, args.objectName)
380 
381 if __name__ == "__main__":
382  main();
CreateClassesForFolder._toCamelCase
def _toCamelCase(identifier)
Definition: CreateClassesForFolder.py:232
vtune_athena.format
format
Definition: vtune_athena.py:14
upper
int upper(int c)
Definition: LArBadChannelParser.cxx:49
CreateClassesForFolder._createAttrConstructorList
def _createAttrConstructorList(nameList)
Definition: CreateClassesForFolder.py:277
covarianceTool.filter
filter
Definition: covarianceTool.py:514
CreateClassesForFolder.add_args
def add_args(parser)
Definition: CreateClassesForFolder.py:209
CreateClassesForFolder._createGetterList
def _createGetterList(nameTypeList)
Definition: CreateClassesForFolder.py:256
CreateClassesForFolder._createDefineSpecificationList
def _createDefineSpecificationList(nameTypeList)
Definition: CreateClassesForFolder.py:242
CreateClassesForFolder._writeToFile
def _writeToFile(fname, template, mapping)
Definition: CreateClassesForFolder.py:284
CreateClassesForFolder.main
def main()
Definition: CreateClassesForFolder.py:364
CreateClassesForFolder._createReadSpecificationList
def _createReadSpecificationList(nameTypeList)
Definition: CreateClassesForFolder.py:249
CreateClassesForFolder._createSetterList
def _createSetterList(nameTypeList)
Definition: CreateClassesForFolder.py:263
CreateClassesForFolder._mapToCpp
def _mapToCpp(t)
Definition: CreateClassesForFolder.py:219
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
CreateClassesForFolder._createAddSpecificationList
def _createAddSpecificationList(nameList)
Definition: CreateClassesForFolder.py:235
Trk::open
@ open
Definition: BinningType.h:40
RCU::substitute
std::string substitute(const std::string &str, const std::string &pattern, const std::string &with)
effects: substitute all occurences of "pattern" with "with" in the string "str" returns: the substitu...
Definition: StringUtil.cxx:24
str
Definition: BTagTrackIpAccessor.cxx:11
CreateClassesForFolder._createAttrDefinitions
def _createAttrDefinitions(nameTypeList)
Definition: CreateClassesForFolder.py:270
Trk::split
@ split
Definition: LayerMaterialProperties.h:38
CreateClassesForFolder.create_classes_from_folder
def create_classes_from_folder(folder, attrExcludeList, attrIncludeList, containerName, objectName)
Definition: CreateClassesForFolder.py:289