Skip to content
Snippets Groups Projects

Added option to ignore C++ defaults when comparing config files

Merged Tomasz Bold requested to merge tbold/athena:remove-defaults-from-diffs into master
2 files
+ 74
6
Compare changes
  • Side-by-side
  • Inline
Files
2
@@ -16,7 +16,9 @@ from AthenaConfiguration.iconfTool.models.element import (
@@ -16,7 +16,9 @@ from AthenaConfiguration.iconfTool.models.element import (
)
)
from AthenaConfiguration.iconfTool.models.structure import ComponentsStructure
from AthenaConfiguration.iconfTool.models.structure import ComponentsStructure
logger = logging.getLogger(__name__)
logger = logging.getLogger("confTool")
 
logger.setLevel(level=logging.INFO)
 
logger.addHandler(logging.FileHandler("confTool-last-run.log", mode='w'))
componentRenamingDict={}
componentRenamingDict={}
@@ -65,22 +67,37 @@ baseParser.add_argument(
@@ -65,22 +67,37 @@ baseParser.add_argument(
help="Pass the file containing remaps",
help="Pass the file containing remaps",
)
)
 
baseParser.add_argument(
 
"--ignoreDefaults",
 
help="Ignore values that are identical to the c++ defaults. Use it only when when the same release is setup as the one used to generate the config.",
 
action="store_true"
 
)
 
baseParser.add_argument(
baseParser.add_argument(
"--shortenDefaultComponents",
"--shortenDefaultComponents",
help="Automatically shorten componet names that have a default name i.e. ToolX/ToolX to ToolX. It helps comparing Run2 & Run3 configurations where these are handled differently",
help="Automatically shorten componet names that have a default name i.e. ToolX/ToolX to ToolX. It helps comparing Run2 & Run3 configurations where these are handled differently",
action="store_true",
action="store_true",
)
)
 
baseParser.add_argument(
 
"--debug",
 
help="Enable tool debugging messages",
 
action="store_true",
 
)
 
def loadConfigFile(fname, args) -> Dict:
def loadConfigFile(fname, args) -> Dict:
"""loads config file into a dictionary, supports several modifications of the input switched on via additional arguments
"""loads config file into a dictionary, supports several modifications of the input switched on via additional arguments
Supports reading: Pickled file with the CA or properties & JSON
Supports reading: Pickled file with the CA or properties & JSON
"""
"""
 
if args.debug:
 
logger.setLevel(logging.DEBUG)
 
conf = {}
conf = {}
if fname.endswith(".pkl"):
if fname.endswith(".pkl"):
with open(fname, "rb") as input_file:
with open(fname, "rb") as input_file:
# determine if there is a old or new configuration pickled
# determine if there is a old or new configuration pickled
cfg = pickle.load(input_file)
cfg = pickle.load(input_file)
print("... Read", cfg.__class__.__name__, "from", fname)
logger.info("... Read %s from %s", cfg.__class__.__name__, fname)
from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
if isinstance(cfg, ComponentAccumulator): # new configuration
if isinstance(cfg, ComponentAccumulator): # new configuration
props = cfg.gatherProps()
props = cfg.gatherProps()
@@ -103,7 +120,7 @@ def loadConfigFile(fname, args) -> Dict:
@@ -103,7 +120,7 @@ def loadConfigFile(fname, args) -> Dict:
elif isinstance(cfg, (collections.Sequence)):
elif isinstance(cfg, (collections.Sequence)):
for c in cfg:
for c in cfg:
conf.update(c)
conf.update(c)
print("... Read", len(conf), "items from python pickle file: ", fname)
logger.info("... Read %d items from python pickle file: %s", len(conf), fname)
elif fname.endswith(".json"):
elif fname.endswith(".json"):
@@ -124,7 +141,7 @@ def loadConfigFile(fname, args) -> Dict:
@@ -124,7 +141,7 @@ def loadConfigFile(fname, args) -> Dict:
for c in cfg:
for c in cfg:
conf.update(cfg)
conf.update(cfg)
print("... Read", len(conf), "items from JSON file: ", fname)
logger.info("... Read %d items from python pickle file: %s", len(conf), fname)
else:
else:
sys.exit("File format not supported.")
sys.exit("File format not supported.")
@@ -155,6 +172,9 @@ def loadConfigFile(fname, args) -> Dict:
@@ -155,6 +172,9 @@ def loadConfigFile(fname, args) -> Dict:
for (key, value) in dic.items():
for (key, value) in dic.items():
if eligible(key):
if eligible(key):
conf[key] = value
conf[key] = value
 
else:
 
logger.debug("Ignored component %s", key)
 
if args.ignoreIrrelevant:
if args.ignoreIrrelevant:
def remove_irrelevant(val_dict):
def remove_irrelevant(val_dict):
@@ -192,6 +212,54 @@ def loadConfigFile(fname, args) -> Dict:
@@ -192,6 +212,54 @@ def loadConfigFile(fname, args) -> Dict:
conf = {}
conf = {}
for (key, value) in dic.items():
for (key, value) in dic.items():
conf[rename_comps(key)] = value
conf[rename_comps(key)] = value
 
 
if args.ignoreDefaults:
 
name_to_type=dict()
 
dic = conf
 
conf = {}
 
 
def drop_defaults(component_name, val_dict):
 
# try picking the name from the dict, if missing use last part of the name, if that fails use the componet_name (heuristic)
 
component_name_last_part = component_name.split(".")[-1]
 
component_type = name_to_type.get(component_name, name_to_type.get(component_name_last_part, component_name_last_part))
 
comp_cls = None
 
try:
 
from AthenaConfiguration.ComponentFactory import CompFactory
 
comp_cls = CompFactory.getComp(component_type)
 
except Exception:
 
logger.debug("Could not find the configuration class %s no defaults for are eliminated", component_name)
 
return val_dict
 
c = {}
 
for k,v in val_dict.items():
 
if str(comp_cls._descriptors[k].default) != v:
 
c[k] = v
 
else:
 
logger.debug("Dropped default value %s of property %s in %s", str(v), str(k), component_name)
 
return c
 
 
# collect types for all componets (we look for A/B or lost of A/B strings)
 
def collect_types(value):
 
parseable = False
 
try:
 
s = ast.literal_eval(str(value))
 
parseable = True
 
if isinstance(s, list):
 
for el in s:
 
collect_types(el)
 
except Exception:
 
pass
 
if isinstance(value,str) and "/" in value and not parseable:
 
comp = value.split("/")
 
if len(comp) == 2:
 
name_to_type[comp[1]] = comp[0]
 
if isinstance(value, dict):
 
[ collect_types(v) for v in value.values() ]
 
 
for (key, value) in dic.items():
 
collect_types(value)
 
for (key, value) in dic.items():
 
conf[key] = drop_defaults(key, value)
 
if args.shortenDefaultComponents:
if args.shortenDefaultComponents:
dic = conf
dic = conf
conf = {}
conf = {}
@@ -206,6 +274,7 @@ def loadConfigFile(fname, args) -> Dict:
@@ -206,6 +274,7 @@ def loadConfigFile(fname, args) -> Dict:
if isinstance(value, str):
if isinstance(value, str):
svalue = value.split("/")
svalue = value.split("/")
if len(svalue) == 2 and svalue[0] == svalue[1]:
if len(svalue) == 2 and svalue[0] == svalue[1]:
 
logger.debug("Shortened %s", svalue)
return svalue[0]
return svalue[0]
if isinstance(value, list):
if isinstance(value, list):
return [shorten(el) for el in value]
return [shorten(el) for el in value]
Loading