ATLAS Offline Software
Loading...
Searching...
No Matches
confTool Namespace Reference

Classes

class  fullColor
class  noColor

Functions

 parse_args ()
 main (args)
 _print (conf, color)
 _printComps (conf)
 _structuredPrint (conf, start, args)
 _compareConfig (configRef, configChk, args, color)
 _parseNumericalValues (values)
 _knownDifference (comp, prop, chkVal, refVal)
 _handleComponentsReanaming (refVal)
 _compareComponent (compRef, compChk, prefix, args, component, propname, color)
 _parseIOVDbFolder (definition)
 _compareIOVDbFolders (compRef, compChk, prefix, args, color)

Variables

dict knownDifferences = {}

Function Documentation

◆ _compareComponent()

confTool._compareComponent ( compRef,
compChk,
prefix,
args,
component,
propname,
color )
protected

Definition at line 424 of file confTool.py.

424def _compareComponent(compRef, compChk, prefix, args, component, propname, color):
425 countDifferent=0
426 if isinstance(compRef, dict):
427 allProps = list(set(compRef.keys()) | set(compChk.keys()))
428 allProps.sort()
429
430 for prop in allProps:
431 if prop not in compRef.keys():
432 if not _knownDifference(component, prop, compChk[prop], None):
433 print(f"{prefix}{color.property}{prop} = {color.second}{compChk[prop]} {color.reset} only in 2nd file {color.reset}")
434 countDifferent += 1
435 else:
436 print(f"{prefix}known difference in: {prop}")
437 continue
438
439 if prop not in compChk.keys():
440 if not _knownDifference(component, prop, compRef[prop], None):
441 print(f"{prefix}{color.property}{prop} = {color.first}{compRef[prop]} {color.reset} only in 1st file {color.reset}")
442 countDifferent += 1
443 else:
444 print(f"{prefix}known difference in: {prop}")
445 continue
446
447 refVal = compRef[prop]
448 chkVal = compChk[prop]
449
450 try:
451 refVal = ast.literal_eval(str(refVal)) if refVal else ""
452 chkVal = ast.literal_eval(str(chkVal)) if chkVal else ""
453 except SyntaxError:
454 pass
455 except ValueError:
456 pass # literal_eval exception when parsing particular strings
457
458 refVal = _handleComponentsReanaming( refVal )
459
460 refVal, chkVal = _parseNumericalValues((refVal, chkVal))
461 diffmarker = ""
462 if chkVal == refVal:
463 if not args.printIdenticalPerParameter:
464 continue
465 elif _knownDifference(component, prop, chkVal, refVal):
466 print(f"{prefix}known difference in: {prop}")
467 if not args.printIdenticalPerParameter:
468 continue
469 else:
470 diffmarker = f" {color.difference}<<{color.reset}"
471
472 if not (component == "IOVDbSvc" and prop == "Folders"):
473 print(f"{prefix}{color.property}{prop} = {color.first} {refVal} {color.reset} vs {color.second} {chkVal} {color.reset} {diffmarker}")
474
475 if refVal and ( isinstance(refVal, (list, dict)) ):
476 if component == "IOVDbSvc" and prop == "Folders":
477 countDifferent += _compareIOVDbFolders(refVal, chkVal, "\t", args, color)
478 else:
479 countDifferent += _compareComponent(
480 refVal, chkVal, "\t" + prefix + ">> ", args, component, prop, color
481 )
482
483 elif isinstance(compRef, (list, tuple, set)) and len(compRef) > 1:
484
485 if isinstance(compRef[0], list): # to achieve hashability
486 compRef = [tuple(_parseNumericalValues(el)) for el in compRef]
487
488 if len(compChk) > 0 and isinstance(compChk[0], list):
489 compChk = [tuple(_parseNumericalValues(el)) for el in compChk]
490
491 # return in case results after parsing are now identical
492 if compRef == compChk:
493 return countDifferent
494
495 diffRef = list(set(compRef) - set(compChk))
496 diffChk = list(set(compChk) - set(compRef))
497
498 if diffRef:
499 print(f"{prefix} {color.reset}only in 1st file : {color.first} {diffRef} {color.reset}")
500 countDifferent += 1
501 if diffChk:
502 print(f"{prefix} {color.reset}only in 2nd file : {color.second} {diffChk} {color.reset}")
503 countDifferent += 1
504
505 if len(compRef) == len(compChk):
506 if sorted(compRef) == sorted(compChk):
507 if any(re.match(f"^{regex}$",f"{component}.{propname}") for regex in args.ignoreOrder):
508 print(f"{prefix} : {color.knowndifference} ^^ Different order ignored ^^ {color.reset}")
509 else:
510 print(f"{prefix} : {color.difference} ^^ Different order ^^ {color.reset}")
511 countDifferent += 1
512 else:
513 for i, (refVal, chkVal) in enumerate(zip(compRef, compChk)):
514 if refVal != chkVal:
515 print(f"{prefix} : {color.first} {refVal} {color.reset} vs {color.second} {chkVal} {color.reset} {color.difference}<< at index {i} {color.reset}")
516 countDifferent += _compareComponent(
517 refVal, chkVal, "\t" + prefix + ">> ", args, "", "", color
518 )
519 return countDifferent
520
void print(char *figname, TCanvas *c1)
STL class.

◆ _compareConfig()

confTool._compareConfig ( configRef,
configChk,
args,
color )
protected

Definition at line 323 of file confTool.py.

323def _compareConfig(configRef, configChk, args, color):
324 # Find superset of all components:
325 allComps = list(set(configRef.keys()) | set(configChk.keys()))
326 allComps.sort()
327
328 print("Step 1: reference file #components:", len(configRef))
329 print("Step 2: file to check #components:", len(configChk))
330 print("Legend:")
331 print(f"{color.difference}Differences in components {color.first}Settings in 1st file {color.second}Settings in 2nd file{color.reset}")
332
333 componentReverseRenamig = {v: k for k, v in componentRenamingDict.items()} # need mapping from new name to old when renaming
334 def _componentDescription(comp_name):
335 return (comp_name+ " renamed from " + componentReverseRenamig[comp_name]) if comp_name in componentReverseRenamig else comp_name
336
337 countDifferent = 0
338 for component in allComps:
339 if component not in configRef:
340 if not args.ignoreMissing:
341 print(
342 f"\n{color.second} Component ",
343 _componentDescription(component),
344 f"{color.reset} only in 2nd file {color.reset} \n",
345 )
346 continue
347
348 if component not in configChk:
349 if not args.ignoreMissing:
350 print(
351 f"\n{color.first} Component",
352 _componentDescription(component),
353 f"{color.reset}only in 1st file {color.reset} \n",
354 )
355 continue
356
357 refValue = configRef[component]
358 chkValue = configChk[component]
359
360 if chkValue == refValue:
361 if args.printIdenticalComponents:
362 print("Component", _componentDescription(component), "identical")
363 else:
364 print(f"{color.difference}Component", _componentDescription(component), f"may differ{color.reset}")
365 if not args.allComponentPrint:
366 countDifferent = _compareComponent(refValue, chkValue, "\t", args, component, "", color)
367 if countDifferent == 0:
368 print(" but all are suppressed by renaming/known differences/...")
369 else:
370 print(f" {color.difference} {countDifferent} relevant differences{color.reset}")
371 else:
372 print(
373 f"\t{color.first}Ref{color.reset}\t",
374 sorted(configRef[component].items(), key=lambda kv: kv[0]),
375 )
376 print(
377 f"\t{color.second}Chk{color.reset}\t",
378 sorted(configChk[component].items(), key=lambda kv: kv[0]),
379 )
380 return countDifferent
381
382

◆ _compareIOVDbFolders()

confTool._compareIOVDbFolders ( compRef,
compChk,
prefix,
args,
color )
protected

Definition at line 553 of file confTool.py.

553def _compareIOVDbFolders(compRef, compChk, prefix, args, color):
554 refParsed = []
555 chkParsed = []
556 for item in compRef:
557 refParsed.append(_parseIOVDbFolder(item))
558 for item in compChk:
559 chkParsed.append(_parseIOVDbFolder(item))
560 return _compareComponent(refParsed, chkParsed, prefix, args, "", "", color)
561
562

◆ _handleComponentsReanaming()

confTool._handleComponentsReanaming ( refVal)
protected
Rename values in reference as long as they are hashable (and in renamingDict)
   It is a bit of heuristics that is invoved, the assumption is that the property has value of the form A/B if it is name of the compoemnt or it is a just single string

Definition at line 407 of file confTool.py.

407def _handleComponentsReanaming( refVal ):
408 """ Rename values in reference as long as they are hashable (and in renamingDict)
409 It is a bit of heuristics that is invoved, the assumption is that the property has value of the form A/B if it is name of the compoemnt or it is a just single string"""
410 refList = refVal if isinstance(refVal, list) else [refVal]
411 updatedRef = []
412 for v in refList:
413 if isinstance(v, str):
414 if "/" in v and len(v.split("/")) == 2:
415 compType,compName = v.split("/")
416 newName = componentRenamingDict.get(compName, compName)
417 updatedRef.append( f"{compType}/{newName}" )
418 else:
419 updatedRef.append( componentRenamingDict.get(v, v) )
420 else:
421 updatedRef.append(v)
422 return updatedRef if isinstance(refVal, list) else updatedRef[0]
423

◆ _knownDifference()

confTool._knownDifference ( comp,
prop,
chkVal,
refVal )
protected

Definition at line 393 of file confTool.py.

393def _knownDifference(comp, prop, chkVal, refVal):
394 if comp in knownDifferences:
395 if prop in knownDifferences[comp]:
396 acceptedDifference = knownDifferences[comp][prop]
397 if acceptedDifference == (None,None):
398 return True
399 if acceptedDifference[0] is None:
400 return chkVal == acceptedDifference[1]
401 if acceptedDifference[1] is None:
402 return refVal == acceptedDifference[0]
403 else:
404 return refVal == acceptedDifference[0] and chkVal == acceptedDifference[1]
405 return False
406

◆ _parseIOVDbFolder()

confTool._parseIOVDbFolder ( definition)
protected

Definition at line 521 of file confTool.py.

521def _parseIOVDbFolder(definition):
522 result = {}
523 # db
524 db_match = re.search(r"<db>(.*)</db>", definition)
525 if db_match:
526 result["db"] = db_match.group(1)
527 definition = definition.replace(db_match.group(0), "")
528 # key
529 key_match = re.search(r"<key>(.*)</key>", definition)
530 if key_match:
531 result["key"] = key_match.group(1)
532 definition = definition.replace(key_match.group(0), "")
533 # tag
534 tag_match = re.search(r"<tag>(.*)</tag>", definition)
535 if tag_match:
536 result["tag"] = tag_match.group(1)
537 definition = definition.replace(tag_match.group(0), "")
538 # cache -- ignore for now
539 cache_match = re.search(r"<cache>(.*)</cache>", definition)
540 if cache_match:
541 definition = definition.replace(cache_match.group(0), "")
542 # noover
543 noover_match = re.search(r"<noover/>", definition)
544 if noover_match:
545 result["noover"] = True
546 definition = definition.replace(noover_match.group(0), "")
547 # name
548 result["name"] = definition.strip()
549
550 return json.dumps(result)
551
552

◆ _parseNumericalValues()

confTool._parseNumericalValues ( values)
protected
Ensure all numeric values are of the same type (int or float)

Definition at line 383 of file confTool.py.

383def _parseNumericalValues(values):
384 """Ensure all numeric values are of the same type (int or float)"""
385 if any(isinstance(val, float) for val in values):
386 return tuple(float(val) for val in values)
387 elif all(isinstance(val, int) for val in values):
388 return tuple(int(val) for val in values)
389 else:
390 return values
391
392

◆ _print()

confTool._print ( conf,
color )
protected

Definition at line 194 of file confTool.py.

194def _print(conf, color):
195 for k, settings in conf.items():
196 print(f"{color.component}{k}{color.reset}")
197 if isinstance(settings, dict):
198 for prop,val in settings.items():
199 print(f" {color.property}{prop} = {color.value}{val}")
200 else:
201 print(settings)
202

◆ _printComps()

confTool._printComps ( conf)
protected

Definition at line 203 of file confTool.py.

203def _printComps(conf):
204 for k, item in conf.items():
205 if isinstance(item, dict):
206 print(k)
207

◆ _structuredPrint()

confTool._structuredPrint ( conf,
start,
args )
protected

Definition at line 208 of file confTool.py.

208def _structuredPrint(conf, start, args):
209 showClasses = args.classes or args.uniqueClasses
210 def _oneCompPrint(d, comp, cl, done={}, depth=0, indent = "") -> list:
211 show = ((not showClasses or cl is not None) and
212 (depth>0 and any([re.match(f"({regex})$",cl) for regex in args.includeClassesSub])) or
213 ((not args.includeClasses or any([re.match(f"({regex})$",cl) for regex in args.includeClasses])) and
214 not any([re.match(f"({regex})$",cl) for regex in args.excludeClasses]) and
215 not any([re.match(f"({regex})$",comp) for regex in args.excludeComponents])))
216 if show:
217 if not args.uniqueClasses:
218 if args.classes:
219 cc = cl if (not args.showComponentName) else f"{cl}/{comp}"
220 print(f"{indent}{cc}")
221 else:
222 print(f"{indent}{comp}")
223 newindent = indent + " - "
224 depth += 1
225 elif args.includeSequences and ((len(d) == 1 and "Members" in d) or (comp == "ApplicationMgr" and "TopAlg" in d)):
226 newindent = indent
227 else:
228 return []
229 if showClasses and args.maxDepth is not None and depth > args.maxDepth:
230 return []
231
232 sub = []
233 for prop,val in sorted(d.items()):
234 if not showClasses and show:
235 print(f"{indent} {prop} = {val}")
236 if args.maxDepth is not None and depth > args.maxDepth:
237 continue
238 if not args.includeSequences and (prop == "Members" or prop == "TopAlg"):
239 continue
240 for ref,c in isReference(val, comp, conf):
241 if showClasses and not c:
242 continue
243 if ref in conf and ref not in done:
244 r = _oneCompPrint(conf[ref], ref, c or ref, {**done, ref:True}, depth, newindent)
245 if args.uniqueClasses:
246 sub += r
247 if show:
248 return [[cl, comp, sub]]
249 else:
250 return sub
251
252 sub = []
253 for comp in start:
254 for ref,cl in isReference(start, None, conf) or [(None,None)]:
255 if ref and ref in conf:
256 settings = conf.get(ref)
257 if isinstance(settings, dict):
258 r = _oneCompPrint(settings, ref, cl or ref)
259 sub += r
260 elif not showClasses:
261 print(settings)
262 else:
263 print(f"{comp} is absent in the config, unfortunately the name has to be exact")
264
265 if not args.uniqueClasses:
266 return
267
268 def _nocomp(top):
269 """copy structure without the component names, so equality tests for the same class names."""
270 new = []
271 for cl,_,sub in top:
272 r = _nocomp(sub)
273 new.append([cl,r])
274 return new
275
276 from collections import defaultdict
277 cls = defaultdict(list)
278 def _oneCompPrune(top):
279 """Duplicate classes (with identical structure below) are listed, without substructure
280 - or not listed at all if they already showed up at this level.
281 Classes with the same name are grouped next to each other and shown with their component name."""
282
283 # group classes with the same name together
284 ord = defaultdict(list)
285 for cl,comp,sub in top:
286 ord[cl].append([cl,comp,sub])
287
288 # remove duplicate class structures
289 new = []
290 dupcls = defaultdict(int)
291 for o in ord.values():
292 for cl,comp,sub in o:
293 comp = comp.split('.')[-1]
294 nsub = _nocomp(sub)
295 if cl in cls and nsub in cls[cl]:
296 if cl in dupcls:
297 continue
298 r = []
299 else:
300 cls[cl].append(nsub)
301 r = _oneCompPrune(sub)
302 dupcls[cl] += 1
303 new.append([cl,comp,r])
304
305 # only show component for duplicated class names
306 if not args.showComponentName:
307 for e in new:
308 if dupcls[e[0]] < 2:
309 e[1] = None
310 return new
311
312 def _structPrint(top, indent = ""):
313 for cl,comp,sub in top:
314 cc = f"{cl}/{comp}" if args.showComponentName else \
315 f"{cl} ({comp})" if comp is not None else cl
316 print(f"{indent}{cc}")
317 if sub:
318 _structPrint(sub, indent + " - ")
319
320 _structPrint(_oneCompPrune(sub))
321
322

◆ main()

confTool.main ( args)

Definition at line 129 of file confTool.py.

129def main(args):
130 exit_code = 0
131 if not args.quiet and args.ignoreIrrelevant:
132 print(f"Properties to ignore: {args.ignore}")
133 color = fullColor()
134 if not sys.stdout.isatty() and not args.color: #Remove colors when writing to a file unless forced
135 color = noColor()
136 if args.printComps:
137 for fileName in args.file:
138 conf = loadConfigFile(fileName, args)
139 _printComps(conf)
140
141 if args.printConf:
142 for fileName in args.file:
143 conf = loadConfigFile(fileName, args)
144 _print(conf, color)
145
146 if args.structured:
147 for fileName in args.file:
148 conf = loadConfigFile(fileName, args)
149 _structuredPrint(conf, args.structured, args)
150
151 if args.toJSON or args.toYAML or args.toPickle:
152 if len(args.file) != 1:
153 sys.exit(
154 "ERROR, can convert single file at a time, got: %s" % args.file
155 )
156 conf = loadConfigFile(args.file[0], args)
157
158 if args.toJSON:
159 oFileName = args.file[0].replace(".pkl", ".json")
160 with open(oFileName, "w") as oFile:
161 json.dump(conf, oFile, indent=4, sort_keys=True, ensure_ascii=True)
162
163 if args.toYAML:
164 oFileName = args.file[0].replace(".pkl", ".yml")
165 with open(oFileName, 'w') as oFile:
166 yaml.dump(conf, oFile, default_flow_style=False)
167
168 if args.toPickle:
169 oFileName = args.file[0].replace(".json", ".pkl")
170 with open(oFileName, "wb") as oFile:
171 for item in conf:
172 pickle.dump(item, oFile)
173 print("Wrote " + args.file[0] + " to " + oFileName)
174
175 if args.diff:
176 if len(args.file) != 2:
177 sys.exit(
178 "ERROR, can diff exactly two files at a time, got: %s"
179 % args.file
180 )
181 # renaming only applied on the "reference/1st" file
182 configRef = loadConfigFile(args.file[0], args)
183 args.renameComps=None
184 args.renameCompsFile=None
185 configChk = loadConfigFile(args.file[1], args)
186 global knownDifferences
187 if args.knownDifferencesFile:
188 knownDifferences = loadDifferencesFile(args.knownDifferencesFile)
189 exit_code = _compareConfig(configRef, configChk, args, color) != 0
190
191 return exit_code
192
193
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition hcg.cxx:310
int main()
Definition hello.cxx:18

◆ parse_args()

confTool.parse_args ( )

Definition at line 36 of file confTool.py.

36def parse_args():
37 parser = baseParser
38 parser.add_argument(
39 "-q", "--quiet", action="store_true", help="Don't print command arguments"
40 )
41 parser.add_argument(
42 "-p", "--printConf", action="store_true", help="Prints entire configuration"
43 )
44 parser.add_argument(
45 "--printComps", action="store_true", help="Prints only the components"
46 )
47 parser.add_argument(
48 "--diff", dest="diff", action="store_true", help="Diffs two files"
49 )
50 parser.add_argument("--toJSON", action="store_true", help="Convert pickle to JSON file")
51 parser.add_argument("--toYAML", action="store_true", help="Convert pickle to YAML file")
52 parser.add_argument("--toPickle", action="store_true", help="Convert JSON to pickle file")
53
54 parser.add_argument("file", nargs="+", help="Files to work with")
55 parser.add_argument(
56 "--ignoreMissing",
57 help="Don't report components existing in only one of the two configurations",
58 action="store_true",
59 )
60 parser.add_argument(
61 "--ignoreOrder",
62 metavar="PROP",
63 action="append",
64 default=[],
65 help="Ignore order for sequence properties matching regex",
66 )
67 parser.add_argument(
68 "--allComponentPrint",
69 help="Print all component if there are differences in any of its properties",
70 action="store_true",
71 )
72 parser.add_argument(
73 "--printIdenticalComponents",
74 help="Print all components even, if there are no differences.",
75 action="store_true",
76 )
77 parser.add_argument(
78 "--printIdenticalPerParameter",
79 help="Print all parameters in component with difference even, if there are no differences.",
80 action="store_true",
81 )
82 parser.add_argument("--knownDifferencesFile",
83 help="Ignore differences enlisted in file (to be used only with diffing)")
84
85 parser.add_argument("--color",
86 help="Use colored output even for file output (useful when piping to less -R to to HTML conversion",
87 action="store_true")
88
89 parser.add_argument("-s", "--structured",
90 action='append',
91 default=[],
92 help="Print only a single component, in a structured manner (reflecting components parent children)")
93
94 parser.add_argument("--includeClassesSub",
95 action='append',
96 default=[],
97 help="Below the top-level, also include the components selected by the given classname (anchored regular expression)")
98
99 parser.add_argument("--includeSequences",
100 help="Include sequences in the structured printout",
101 action="store_true")
102
103 parser.add_argument("--classes",
104 action="store_true",
105 help="Only show class names")
106
107 parser.add_argument("--uniqueClasses",
108 action="store_true",
109 help="Only show unique classes")
110
111 parser.add_argument("--showComponentName",
112 help="Show component name with --classes",
113 action="store_true")
114
115 parser.add_argument("--maxDepth",
116 help="Maximum depth for structured printout",
117 type=int,
118 default=None)
119
120 args = parser.parse_args()
121 if not args.quiet:
122 print("Run with arguments:")
123 print( "confTool.py", " ".join(sys.argv[1:]))
124
125 return main(args)
126

Variable Documentation

◆ knownDifferences

dict confTool.knownDifferences = {}

Definition at line 127 of file confTool.py.