CMS 3D CMS Logo

ClassesDefXmlUtils.py
Go to the documentation of this file.
2  """Parses a classes_def.xml file looking for class declarations that contain
3  ClassVersion attributes. Once found looks for sub-elements named 'version'
4  which contain the ClassVersion to checksum mappings.
5  """
6 
7  #The following are constants used to describe what data is kept
8  # in which index in the 'classes' member data
9  originalNameIndex=0
10  classVersionIndex=1
11  versionsToChecksumIndex = 2
12 
13  def __init__(self, filename, includeNonVersionedClasses=False, normalizeClassNames=True):
14  self._file = filename
15  self.classes = dict()
16  self._presentClass = None
18  self._includeNonVersionedClasses = includeNonVersionedClasses
19  self._normalizeClassNames = normalizeClassNames
20  self.readClassesDefXML()
21  def readClassesDefXML(self):
22  import xml.parsers.expat
23  p = xml.parsers.expat.ParserCreate()
24  p.StartElementHandler = self.start_element
25  p.EndElementHandler = self.end_element
26  f = open(self._file)
27  # Replace any occurence of <>& in the attribute values by the xml parameter
28  rxml, nxml = f.read(), ''
29  q1,q2 = 0,0
30  for c in rxml :
31  if (q1 or q2) and c == '<' : nxml += '&lt;'
32  elif (q1 or q2) and c == '>' : nxml += '&gt;'
33  # elif (q1 or q2) and c == '&' : nxml += '&amp;'
34  else : nxml += c
35  if c == '"' : q1 = not q1
36  if c == "'" : q2 = not q2
37  try : p.Parse(nxml)
38  except xml.parsers.expat.ExpatError as e :
39  print ('--->> edmCheckClassVersion: ERROR: parsing selection file ',self._file)
40  print ('--->> edmCheckClassVersion: ERROR: Error is:', e)
41  raise
42  f.close()
43  def start_element(self,name,attrs):
44  if name in ('class','struct'):
45  if 'name' in attrs:
46  self._presentClass=attrs['name']
47  normalizedName = self.genNName(attrs['name'])
48  if 'ClassVersion' in attrs:
49  self.classes[normalizedName]=[attrs['name'],int(attrs['ClassVersion']),[]]
50  self._presentClassForVersion=normalizedName
52  # skip transient data products
53  if not ('persistent' in attrs and attrs['persistent'] == "false"):
54  self.classes[normalizedName]=[attrs['name'],-1,[]]
55  else:
56  raise RuntimeError(f"There is an element '{name}' without 'name' attribute.")
57  if name == 'version':
58  if self._presentClassForVersion is None:
59  raise RuntimeError(f"Class element for type '{self._presentClass}' contains a 'version' element, but 'ClassVersion' attribute is missing from the 'class' element")
60  try:
61  classVersion = int(attrs['ClassVersion'])
62  except KeyError:
63  raise RuntimeError(f"Version element for type '{self._presentClass}' is missing 'ClassVersion' attribute")
64  try:
65  checksum = int(attrs['checksum'])
66  except KeyError:
67  raise RuntimeError(f"Version element for type '{self._presentClass}' is missing 'checksum' attribute")
68  self.classes[self._presentClassForVersion][XmlParser.versionsToChecksumIndex].append([classVersion, checksum])
69  pass
70  def end_element(self,name):
71  if name in ('class','struct'):
72  self._presentClass = None
73  self._presentClassForVersion = None
74  def genNName(self, name ):
75  if not self._normalizeClassNames:
76  return name
77  n_name = " ".join(name.split())
78  for e in [ ['long long unsigned int', 'unsigned long long'],
79  ['long long int', 'long long'],
80  ['unsigned short int', 'unsigned short'],
81  ['short unsigned int', 'unsigned short'],
82  ['short int', 'short'],
83  ['long unsigned int', 'unsigned long'],
84  ['unsigned long int', 'unsigned long'],
85  ['long int', 'long'],
86  ['std::string', 'std::basic_string<char>']] :
87  n_name = n_name.replace(e[0],e[1])
88  n_name = n_name.replace(' ','')
89  return n_name
90 
91 def initROOT(library):
92  #Need to not have ROOT load .rootlogon.(C|py) since it can cause interference.
93  import ROOT
94  ROOT.PyConfig.DisableRootLogon = True
95 
96  #Keep ROOT from trying to use X11
97  ROOT.gROOT.SetBatch(True)
98  ROOT.gROOT.ProcessLine(".autodict")
99  if library is not None:
100  if ROOT.gSystem.Load(library) < 0 :
101  raise RuntimeError("failed to load library '"+library+"'")
102 
104  """Must be called before checkClass()"""
105  import ROOT
106  ROOT.gROOT.ProcessLine("class checkclass {public: int f(char const* name) {TClass* cl = TClass::GetClass(name); bool b = false; cl->GetCheckSum(b); return (int)b;} };")
107  ROOT.gROOT.ProcessLine("checkclass checkTheClass;")
108 
109 
110 #The following are error codes returned from checkClass
111 noError = 0
112 errorRootDoesNotMatchClassDef =1
113 errorMustUpdateClassVersion=2
114 errorMustAddChecksum=3
115 
116 def checkClass(name,version,versionsToChecksums):
117  import ROOT
118  c = ROOT.TClass.GetClass(name)
119  if not c:
120  raise RuntimeError("failed to load dictionary for class '"+name+"'")
121  temp = "checkTheClass.f(" + '"' + name + '"' + ");"
122  retval = ROOT.gROOT.ProcessLine(temp)
123  if retval == 0 :
124  raise RuntimeError("TClass::GetCheckSum: Failed to load dictionary for base class. See previous Error message")
125  classChecksum = c.GetCheckSum()
126  classVersion = c.GetClassVersion()
127 
128  #does this version match what is in the file?
129  if version != classVersion:
130  return (errorRootDoesNotMatchClassDef,classVersion,classChecksum)
131 
132  #is the version already in our list?
133  found = False
134 
135  for v,cs in versionsToChecksums:
136  if v == version:
137  found = True
138  if classChecksum != cs:
139  return (errorMustUpdateClassVersion,classVersion,classChecksum)
140  break
141  if not found and classVersion != 0:
142  return (errorMustAddChecksum,classVersion,classChecksum)
143  return (noError,classVersion,classChecksum)
def checkClass(name, version, versionsToChecksums)
def start_element(self, name, attrs)
static std::string join(char **cmd)
Definition: RemoteFile.cc:21
def __init__(self, filename, includeNonVersionedClasses=False, normalizeClassNames=True)