1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
#! /usr/bin/env python3
import string
import re
import collections
classtransients = collections.defaultdict(list)
classtransients['edm::AssociationMap'].append('transientMap_')
classtransients['edm::AssociationVector'].append('transientVector_')
class RMParser(object):
"""Parses the rootmap file(s) for a package looking for class declarations of edm template classes
which contain member(s) which must be labeled transient="true" in classes_def.xml
"""
def __init__(self,filelist):
self._files = filelist
self.cnames = collections.defaultdict(list)
self._presentClass = None
self.readRootMap()
def readRootMap(self):
for filename in self._files:
f = open(filename)
for line in f:
cname=""
if re.search("^class",line): cname = re.sub("class ","",line)
if re.search("^struct",line): cname = re.sub("struct ","",line)
for key in classtransients.keys():
if re.search(r'^%s<' % key, cname):
n_name = " ".join(line.split())
self.cnames[key].append(n_name)
f.close()
def checkTrans(templname,name):
c = ROOT.TClass.GetClass(name)
if not c:
print ("Info: Could no load dictionary for class '"+name+"' because of typedef(s) in the name.")
return 0
nerrs=0
for trans in classtransients[templname]:
tdm = c.GetDataMember(trans)
retval = False
if tdm : retval = tdm.IsPersistent()
if retval == True :
print ("Error: field='"+trans+"' must be labeled transient=\"true\" in classes_def.xml for "+name+" or the equivalent class name with typedefs.")
nerrs+=1
return nerrs
#Setup the options
from argparse import ArgumentParser
oparser = ArgumentParser()
oparser.add_argument("-l","--lib", dest="library", type=str,
help="specify the library to load")
oparser.add_argument("-f","--rootmap", dest="rmfiles", action="append", type=str, default=[],
help="specify the rootmap file(s) to read")
options=oparser.parse_args()
#Need to not have ROOT load .rootlogon.(C|py) since it can cause interference.
import ROOT
ROOT.PyConfig.DisableRootLogon = True
#Keep ROOT from trying to use X11
ROOT.gROOT.SetBatch(True)
ROOT.gROOT.ProcessLine(".autodict")
if options.library is None:
print ("Transient member check requires a specific library")
else:
if ROOT.gSystem.Load(options.library) < 0 :
raise RuntimeError("failed to load library '"+options.library+"'")
p = RMParser(options.rmfiles)
nerrs = 0
for key in p.cnames.keys():
for value in p.cnames[key]:
nerrs += checkTrans(key,value)
if nerrs > 0 :
print ("Error: edm template class member must be labeled transient=\"true\" in classes_def.xml. Check log for specific template and member name.")
import sys
sys.exit(1)
|