ATLAS Offline Software
Loading...
Searching...
No Matches
han_lark_tester.py
Go to the documentation of this file.
1#!/usr/bin/env python
2# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3
4# More detailed syntax checking for han files
5
6
7import lark, sys
8from AthenaCommon.Utils.unixtools import find_datafile
9
10class T(lark.Transformer):
11 def __init__(self):
12 super().__init__()
14
15 def __default_token__(self,tok):
16 print(tok)
17 return tok
18 def referenceblock(self, tok):
19 locations = [_ for _ in tok if isinstance(_, lark.Tree) and _.data == 'location']
20 if len(locations) > 1:
21 raise ValueError(f'More than one location given for reference {tok[0].children[0]}')
22 if len(locations) > 0:
23 locs = locations[0].children[0].split(',')
24 else:
25 locs = [_.children[0] for _ in tok if isinstance(_, lark.Tree) and _.data == 'file']
26 afspaths = [_ for _ in locs if _.startswith('/afs')]
27 if any(afspaths):
28 raise ValueError('A reference location for a production han configuration is given with an AFS path\n'
29 f'Offending path is {",".join(afspaths)} of reference {tok[0].children[0]}')
30 eospaths = [_ for _ in locs if _.startswith('/eos')]
31 xrootdpaths = [_ for _ in locs if _.startswith('root://')]
32 if len(eospaths) != len(xrootdpaths):
33 raise ValueError(f'Backup xrootd locations must be given for references with EOS paths for reference {tok[0].children[0]}\n'
34 f'Given EOS paths are {",".join(eospaths)}\n'
35 f'Given xrootd paths are {",".join(xrootdpaths)}')
36 return tok
37
38
39class AlgorithmNameInterpreter(lark.visitors.Interpreter):
40 def __init__(self):
41 super().__init__()
42
43 def algorithmblock(self, tree: lark.Tree):
44 thisalgname = [_.children[0].value for _ in tree.children if isinstance(_, lark.Tree) and _.data == "algorithmname"][0]
45 thisalgrealname = [_ for _ in tree.children if isinstance(_, lark.Tree) and _.data == "realname"]
46 if not thisalgrealname:
47 raise ValueError(f"no underlying algorithm specified for {thisalgname}")
48 for node in tree.children:
49 if node.data == 'algorithmblock':
50 for subnode in node.children:
51 if subnode.data == 'algorithmname':
52 subnode.children[0].value = thisalgname + '/' + subnode.children[0].value
53 if not [_ for _ in node.children if isinstance(_, lark.Tree) and _.data == "realname"]:
54 node.children.append(thisalgrealname[0])
55 self.visit(node)
56
57 def dirblock(self, tree: lark.Tree):
58 thisdirname = [_.children[0].value for _ in tree.children if isinstance(_, lark.Tree) and _.data == "dirname"][0]
59 for node in tree.children:
60 if node.data == 'dirblock':
61 for subnode in node.children:
62 if subnode.data == 'dirname':
63 subnode.children[0].value = thisdirname + '/' + subnode.children[0].value
64 self.visit(node)
65 elif node.data == 'histblock':
66 for subnode in node.children:
67 if subnode.data == 'histname':
68 subnode.children[0].value = thisdirname + '/' + subnode.children[0].value
69
70
71grammarfile = find_datafile('DataQualityInterfaces/han_def.lark')
72if grammarfile is None:
73 raise OSError('Unable to find file parser configuration file')
74grammar = open(grammarfile).read()
75transformer = T()
76parser = lark.Lark(grammar, parser='lalr', lexer='contextual', transformer=transformer)
77
78
80 import ROOT
81 import cppyy
82
83 ROOT.gSystem.Load('libdqm_core.so')
84 cppyy.include("dqm_core/AlgorithmManager.h")
85
86 cppyy.cppdef(r"""
87#include <dqm_core/AlgorithmManager.h>
88std::pair<std::vector<std::string>, std::vector<std::string>> get_lib_algs() {
89std::vector<std::string> rv1;
90std::vector<std::string> rv2;
91for (const auto& p : dqm_core::AlgorithmManager::instance().getAlgorithmMap()) {
92 rv1.push_back(p.first);
93}
94for (const auto& p : dqm_core::AlgorithmManager::instance().getSummaryMakerMap()) {
95 rv2.push_back(p.first);
96}
97return std::move(std::make_pair(rv1, rv2));
98}
99"""
100 )
101
102 rv = True
103 try:
104 AlgorithmNameInterpreter().visit(tree)
105 except ValueError as e:
106 print(f'ERROR: {e}')
107 return False
108 libs = {_.children[0].value for _ in tree.find_data('libname')} # Defined libraries
109 compalgs = {_.children[0].value for _ in tree.find_data('compalgname')} # Defined composite algorithms
110
111 # Check if the referenced libraries exist
112 for lib in libs:
113 if ROOT.gSystem.Load(lib) < 0:
114 rv = False
115 print(f'ERROR: Library {lib} defined by a libname clause cannot be found. Referenced by:')
116 for alg in tree.find_data('algorithmblock'):
117 alibname = alg.find_data('libname')
118 if alibname and lib in {_.children[0].value for _ in alibname}:
119 print(list(alg.find_data('algorithmname'))[0].children[0].value)
120
121 # Extract the list of "base" algorithms and summaries
122 libalgos, libsummaries = ROOT.get_lib_algs()
123
124 # Check that the composite algorithms reference existing base algorithms (and not summaries!)
125 for alg in tree.find_data('compalgblock'):
126 subalglist = [_ for _ in alg.children if _.data == 'subalglist']
127 for tok in subalglist[0].children:
128 if tok.value not in libalgos:
129 algname = list(alg.find_data('compalgname'))[0].children[0].value
130 print(f'ERROR: composite algorithm {algname} references {tok.value} which is not a known algorithm')
131 rv = False
132
133 # Check that all the instantiated algorithms and summaries refer to existing base algorithms and summaries
134 instalgos = set()
135 instsummaries = set()
136 for alg in tree.find_data('algorithmblock'):
137 try:
138 algname = [_.children[0].value for _ in alg.children if isinstance(_, lark.Tree) and _.data == "algorithmname"][0]
139 algrealname = [_.children[0].value for _ in alg.children if isinstance(_, lark.Tree) and _.data == "realname"][0]
140 if algrealname in libalgos:
141 instalgos.add(algname)
142 elif algrealname in libsummaries:
143 instsummaries.add(algname)
144 elif algrealname in compalgs:
145 instalgos.add(algname)
146 else:
147 print(f'ERROR: undefined base algorithm {algrealname} for {algname}')
148 rv = False
149 except Exception as e:
150 print('??? problem processing', alg, e)
151
152 # These SHOULD just be summaries
153 for ref in tree.find_data('algorefstatement'):
154 nodealg = ref.children[0].children[0].value
155 if nodealg not in instsummaries:
156 print(f'ERROR: an output is specifying algorithm = {nodealg} which is not a known summary algorithm')
157 rv = False
158
159 # These SHOULD just be non-summary algos
160 for ref in list(tree.find_data('dirblock')) + list(tree.find_data('histblock')):
161 nodealg = [_ for _ in ref.children if _.data == 'algorithmreference']
162 if nodealg:
163 nodealgname = nodealg[0].children[0].value
164 if nodealgname not in instalgos:
165 refname = [_ for _ in ref.children if _.data in ('histname', 'dirname')][0].children[0].value
166 print(f'ERROR: a dir/hist is specifying algorthm = {nodealgname} which is not a known histogram algorithm. Referenced by {refname}')
167 rv = False
168
169 return rv
170
171
172infile = open(sys.argv[1]).read()
173try:
174 tree = parser.parse(infile)
175 print('Tree done')
176 print('Checking algorithms')
177 if algorithm_check(tree):
178 print(tree.pretty())
179 print('All ok')
180 else:
181 sys.exit(1)
182
183except Exception as e:
184 print('ERROR:')
185 print(e)
186 raise e
187 sys.exit(1)
void print(char *figname, TCanvas *c1)
__default_token__(self, tok)
referenceblock(self, tok)
STL class.
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:177
IovVectorMap_t read(const Folder &theFolder, const SelectionCriterion &choice, const unsigned int limit=10)