ATLAS Offline Software
Toggle main menu visibility
Loading...
Searching...
No Matches
PhysicsAnalysis
Algorithms
AnalysisAlgorithmsConfig
python
SaveConfigUtils.py
Go to the documentation of this file.
1
# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2
3
from
AnaAlgorithm.AlgSequence
import
AlgSequence
4
from
AnaAlgorithm.PythonConfig
import
PrivateToolConfig
5
from
AnaAlgorithm.Logging
import
logging
6
7
import
os
8
import
json
9
import
re
10
11
# A tool declaration value has the shape 'Type/Name', with a (possibly namespace-qualified
12
# or templated) C++ type name and a tool name made of identifier components separated by dots
13
_toolDeclarationExpr = re.compile(
r'[A-Za-z_][A-Za-z0-9_:<>,]*/[A-Za-z_][A-Za-z0-9_.]*'
)
14
15
def
combine_tools_and_algorithms_ELjob
(combine_dictionaries = True, text_file = 'tool_config.txt',
16
alg_file = 'alg_sequence.json', output_file = 'my_analysis_config.json'):
17
"""
18
Parse a tool configuration text file and merge it with an algorithm sequence JSON file.
19
20
Args:
21
combine_dictionaries (bool): Whether to load and merge with existing alg_file
22
text_file (str): Path to the tool configuration text file
23
alg_file (str): Path to the algorithm sequence JSON file
24
output_file (str): Path where the merged configuration will be saved
25
26
Returns:
27
dict: The resulting configuration, which is a merge of the tool configuration
28
and algorithm sequence JSON data.
29
"""
30
log = logging.getLogger(
"SaveConfigUtils"
)
31
log.info(
"Calling COMBINE_JSON_FILES with the following arguments:"
)
32
log.info(f
" - tool configuration = {text_file}"
)
33
log.info(f
" - algorithm sequence = {alg_file}"
)
34
log.info(f
" - full output config = {output_file}"
)
35
36
if
not
os.path.exists(text_file):
37
raise
FileNotFoundError(f
"The tool configuration file {text_file} was not found."
)
38
if
not
os.path.exists(alg_file):
39
raise
FileNotFoundError(f
"The algorithm sequence file {alg_file} was not found."
)
40
41
# Load or initialize the configuration
42
config = {}
43
if
combine_dictionaries:
44
with
open(alg_file,
'r'
, encoding=
'utf-8'
)
as
f:
45
try
:
46
config = json.load(f)
47
except
json.JSONDecodeError
as
e:
48
raise
ValueError(f
"Error parsing JSON in {alg_file}: {e}"
)
from
e
49
50
# Process the tool configuration file
51
current_tool_path =
None
52
current_tool_id =
None
53
current_tool_properties = {}
54
55
with
open(text_file,
'r'
)
as
f:
56
for
line
in
f:
57
line = line.strip()
58
if
not
line
or
'='
not
in
line:
59
continue
60
61
path, value =
map
(str.strip, line.split(
'='
, 1))
62
parts = path.split(
'.'
)
63
64
# There are two possibilities for 'parts':
65
# 1. Declaration of a new tool
66
# 2. Setting a property on an existing tool
67
if
_toolDeclarationExpr.fullmatch(value)
and
current_tool_path != parts:
68
# We are in case 1, meaning we are done with the previous tool (if any)
69
# Start by saving the settings of the previous tool
70
_register_settings
(config, current_tool_path, current_tool_id, current_tool_properties)
71
# Then register the new tool
72
tool_path = parts[:-1]
73
tool_id = parts[-1]
74
tool_name = value.split(
"/"
)[1]
75
_register_new_tool
(config, tool_path, tool_id, tool_name)
76
# We are ready to collect information about the new tool
77
current_tool_path = tool_path
78
current_tool_id = tool_id
79
current_tool_properties = {}
80
else
:
81
# We are in case 2: record new settings
82
property_name = parts[-1]
83
current_tool_properties[property_name] = value
84
85
# Register any remaining settings for the last tool if necessary
86
if
current_tool_properties
and
current_tool_id:
87
_register_settings
(config, current_tool_path, current_tool_id, current_tool_properties)
88
89
# Write output
90
with
open(output_file,
'w'
, encoding=
'utf-8'
)
as
f:
91
json.dump(config, f, indent=4)
92
93
return
config
94
95
96
def
_register_settings
(config, path, name, settings):
97
if
not
settings
or
path
is
None
:
return
98
current_dict = config
99
100
# Iterate through the path to reach the correct nested dictionary
101
for
key
in
path:
102
if
key
not
in
current_dict:
103
raise
ValueError(f
"Couldn't find key {key} in dictionary of algorithms and tools, this should not happen!"
)
104
current_dict = current_dict[key][
"Properties"
][
"Tools"
]
105
106
for
key,value
in
settings.items():
107
_safe_add_property
(key, value, current_dict[name])
108
109
110
def
_register_new_tool
(config, path, tool_id, name):
111
current_dict = config
112
113
# Iterate through the path to reach the correct nested dictionary
114
for
key
in
path:
115
if
key
not
in
current_dict:
116
# Create the entry with the appropriate structure
117
current_dict[key] = {
"Properties"
: {
"Tools"
: {}},
"Type"
:
""
}
118
else
:
119
# Enforce the appropriate structure
120
if
"Properties"
not
in
current_dict[key].keys():
121
current_dict[key][
"Properties"
] = {
"Tools"
: {}}
122
if
"Tools"
not
in
current_dict[key][
"Properties"
].keys():
123
current_dict[key][
"Properties"
][
"Tools"
] = {}
124
current_dict = current_dict[key][
"Properties"
][
"Tools"
]
125
126
# Ensure the tool id exists as a key with a dictionary as its value
127
if
tool_id
not
in
current_dict:
128
current_dict[tool_id] = {
"Properties"
: {}}
129
130
# Set the 'Name:' key with the given name
131
if
"Properties"
not
in
current_dict[tool_id]:
132
current_dict[tool_id][
"Properties"
] = {}
133
current_dict[tool_id][
"Properties"
][
"Name"
] = name
134
135
136
def
save_algs_from_sequence_ELjob
(sequence, output_dict):
137
"""
138
Save the algorithms in the sequence without the sequence structure.
139
Does not save the tools. You need to get them with PrintToolConfigAlg.
140
141
Args:
142
sequence (AnaAlgorithm.AlgSequence: the algorithm sequence to parse
143
output_dict (dict): the dictionary to populate
144
"""
145
# Ensure output_dict is a dictionary
146
if
not
isinstance(output_dict, dict):
147
raise
ValueError(
"output_dict must be a dictionary"
)
148
149
# Handle recursive case for AlgSequence
150
if
isinstance(sequence, AlgSequence):
151
for
alg
in
sequence:
152
nested_dict = {}
153
save_algs_from_sequence_ELjob
(alg, nested_dict)
154
output_dict[alg.name()] = nested_dict
155
else
:
156
# Handle the algorithm itself
157
_save_algorithm
(sequence, output_dict)
158
159
160
def
_save_algorithm
(sequence, output_dict):
161
""" Helper function to save individual algorithm properties """
162
output_dict[
'Type'
] = sequence.type()
163
output_dict[
'Properties'
] = {
'Tools'
: {}}
164
165
for
key, value
in
sorted(sequence._props.items()):
166
if
isinstance(value, str):
167
output_dict[
'Properties'
][key] = value
168
elif
isinstance(value, PrivateToolConfig):
169
_handle_tool_config
(value, output_dict)
170
else
:
171
_safe_add_property
(key, value, output_dict)
172
173
174
def
_handle_tool_config
(tool_config, output_dict):
175
""" Handle tool configurations inside algorithms """
176
log = logging.getLogger(
"SaveConfigUtils"
)
177
if
tool_config._prefix
in
output_dict[
'Properties'
][
'Tools'
]:
178
log.warning(f
"Already have this tool in the dict, prefix: {tool_config._prefix}. You need to ID the name somehow."
)
179
else
:
180
output_dict[
'Properties'
][
'Tools'
][tool_config._prefix] = {
'Type'
: tool_config._type}
181
182
183
def
_safe_add_property
(key, value, output_dict):
184
""" Safely adds properties to the output_dict with error handling """
185
log = logging.getLogger(
"SaveConfigUtils"
)
186
try
:
187
output_dict[
'Properties'
][key] = value
188
except
Exception
as
e:
189
log.warning(f
"Couldn't add property '{key}' to dict. Value: {value}. Error: {e}"
)
map
STL class.
python.SaveConfigUtils._register_settings
_register_settings(config, path, name, settings)
Definition
SaveConfigUtils.py:96
python.SaveConfigUtils._safe_add_property
_safe_add_property(key, value, output_dict)
Definition
SaveConfigUtils.py:183
python.SaveConfigUtils._save_algorithm
_save_algorithm(sequence, output_dict)
Definition
SaveConfigUtils.py:160
python.SaveConfigUtils.combine_tools_and_algorithms_ELjob
combine_tools_and_algorithms_ELjob(combine_dictionaries=True, text_file='tool_config.txt', alg_file='alg_sequence.json', output_file='my_analysis_config.json')
Definition
SaveConfigUtils.py:16
python.SaveConfigUtils._handle_tool_config
_handle_tool_config(tool_config, output_dict)
Definition
SaveConfigUtils.py:174
python.SaveConfigUtils.save_algs_from_sequence_ELjob
save_algs_from_sequence_ELjob(sequence, output_dict)
Definition
SaveConfigUtils.py:136
python.SaveConfigUtils._register_new_tool
_register_new_tool(config, path, tool_id, name)
Definition
SaveConfigUtils.py:110
Generated on
for ATLAS Offline Software by
1.17.0