ATLAS Offline Software
Toggle main menu visibility
Loading...
Searching...
No Matches
PhysicsAnalysis
Algorithms
AnalysisAlgorithmsConfig
python
ConfigPropertySubstitution_unitTest.py
Go to the documentation of this file.
1
#!/usr/bin/env python
2
# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3
4
# Unit tests for `ConfigPropertySubstitution`.
5
#
6
# The substitution module exposes two functions used by
7
# `ConfigAccumulator.renameFinalContainers`:
8
# * `substituteValue` — recursively rewrites string references inside
9
# a property value, handling private tools, tool-handle arrays, data
10
# handles, and nested list/dict/set/tuple containers.
11
# * `substituteComponentProperties` — walks a configurable component's
12
# user-set properties and substitutes each value in place.
13
#
14
# The first half of this file exercises `substituteValue` directly on
15
# plain Python data, including the anchored-boundary edge cases. The
16
# second half builds real configurables via the dual-use interface (the
17
# same primitives `ConfigAccumulator` uses internally) and verifies the
18
# substitution lands in algorithm properties and inside a private tool.
19
20
21
import
unittest
22
23
from
AnalysisAlgorithmsConfig.ConfigPropertySubstitution
import
(
24
substituteComponentProperties,
25
substituteValue,
26
)
27
28
29
class
TestSubstituteValue
(unittest.TestCase) :
30
"""Pure tests of `substituteValue` — no configurables involved."""
31
32
SUBS = [(
'Jets_STEP3'
,
'Jets'
)]
33
34
def
test_plain_string_match
(self) :
35
self.assertEqual (substituteValue (
'Jets_STEP3'
, self.
SUBS
),
'Jets'
)
36
37
def
test_plain_string_no_match
(self) :
38
self.assertEqual (substituteValue (
'Electrons_STEP1'
, self.
SUBS
),
39
'Electrons_STEP1'
)
40
41
def
test_string_with_suffix
(self) :
42
# `_%SYS%` follows the match — the leading boundary is still
43
# the start of the string, so this is a valid rewrite.
44
self.assertEqual (substituteValue (
'Jets_STEP3_%SYS%'
, self.
SUBS
),
45
'Jets_%SYS%'
)
46
47
def
test_string_with_trailing_dot
(self) :
48
self.assertEqual (substituteValue (
'Jets_STEP3.flag'
, self.
SUBS
),
49
'Jets.flag'
)
50
51
def
test_anchored_boundary_left
(self) :
52
# The `My` prefix means the char before the match is an
53
# identifier char, so `_anchoredReplace` must NOT match.
54
self.assertEqual (substituteValue (
'MyJets_STEP3'
, self.
SUBS
),
55
'MyJets_STEP3'
)
56
57
def
test_anchored_inside_expression
(self) :
58
# Embedded in a larger expression; the spaces / operator chars
59
# are non-identifier boundaries, so all matches rewrite.
60
self.assertEqual (substituteValue (
'Jets_STEP3.a && Jets_STEP3.b'
,
61
self.
SUBS
),
62
'Jets.a && Jets.b'
)
63
64
def
test_anchored_inside_expression_with_trap
(self) :
65
# The `My`-prefixed term in the middle must survive.
66
self.assertEqual (substituteValue (
'Jets_STEP3 && MyJets_STEP3'
,
67
self.
SUBS
),
68
'Jets && MyJets_STEP3'
)
69
70
def
test_multiple_substitutions_applied_in_order
(self) :
71
subs = [(
'Jets_STEP3'
,
'Jets'
), (
'Electrons_STEP2'
,
'Electrons'
)]
72
self.assertEqual (substituteValue (
'Jets_STEP3 && Electrons_STEP2'
,
73
subs),
74
'Jets && Electrons'
)
75
76
def
test_list_recurses
(self) :
77
result = substituteValue ([
'Jets_STEP3'
,
'MyJets_STEP3'
,
'other'
],
78
self.
SUBS
)
79
self.assertEqual (result, [
'Jets'
,
'MyJets_STEP3'
,
'other'
])
80
self.assertIsInstance (result, list)
81
82
def
test_dict_recurses_on_keys_and_values
(self) :
83
result = substituteValue ({
'Jets_STEP3'
:
'Jets_STEP3.flag'
,
84
'MyJets_STEP3'
:
'unrelated'
},
85
self.
SUBS
)
86
self.assertEqual (result, {
'Jets'
:
'Jets.flag'
,
87
'MyJets_STEP3'
:
'unrelated'
})
88
self.assertIsInstance (result, dict)
89
90
def
test_set_recurses
(self) :
91
result = substituteValue ({
'Jets_STEP3'
,
'MyJets_STEP3'
}, self.
SUBS
)
92
self.assertEqual (result, {
'Jets'
,
'MyJets_STEP3'
})
93
self.assertIsInstance (result, set)
94
95
def
test_tuple_recurses
(self) :
96
result = substituteValue ((
'Jets_STEP3'
,
'MyJets_STEP3'
), self.
SUBS
)
97
self.assertEqual (result, (
'Jets'
,
'MyJets_STEP3'
))
98
self.assertIsInstance (result, tuple)
99
100
def
test_nested_dict_with_list
(self) :
101
value = {
'a'
: [
'Jets_STEP3'
,
'MyJets_STEP3'
],
102
'Jets_STEP3.b'
: {
'c'
:
'Jets_STEP3'
}}
103
self.assertEqual (substituteValue (value, self.
SUBS
),
104
{
'a'
: [
'Jets'
,
'MyJets_STEP3'
],
105
'Jets.b'
: {
'c'
:
'Jets'
}})
106
107
def
test_non_string_scalars_unchanged
(self) :
108
self.assertEqual (substituteValue (42, self.
SUBS
), 42)
109
self.assertEqual (substituteValue (3.14, self.
SUBS
), 3.14)
110
self.assertEqual (substituteValue (
True
, self.
SUBS
),
True
)
111
self.assertIsNone (substituteValue (
None
, self.
SUBS
))
112
113
def
test_empty_substitutions_is_identity
(self) :
114
self.assertEqual (substituteValue (
'Jets_STEP3'
, []),
'Jets_STEP3'
)
115
self.assertEqual (substituteValue ([
'Jets_STEP3'
], []), [
'Jets_STEP3'
])
116
117
118
class
TestSubstituteComponentProperties
(unittest.TestCase) :
119
"""Build real configurables via the dual-use interface — the same
120
primitives `ConfigAccumulator` uses internally — and verify the
121
substitution walks into algorithm properties and a private tool."""
122
123
SUBS = [(
'AnaJets_STEP3'
,
'AnaJets'
)]
124
125
def
_makeAlg
(self) :
126
import
AnaAlgorithm.DualUseConfig
as
DualUseConfig
127
alg = DualUseConfig.createAlgorithm (
128
'CP::AsgSelectionAlg'
,
'TestSelectionAlg'
)
129
DualUseConfig.addPrivateTool (
130
alg,
'selectionTool'
,
'CP::AsgFlagSelectionTool'
)
131
alg.particles =
'AnaJets_STEP3_%SYS%'
132
alg.preselection =
'preselect_STEP3,as_char'
133
alg.selectionDecoration =
'pass_AnaJets_STEP3,as_char'
134
alg.selectionTool.selectionFlags = [
135
'AnaJets_STEP3.flag'
,
136
'MyAnaJets_STEP3.flag'
,
137
'unrelated'
,
138
]
139
return
alg
140
141
def
test_substitution_rewrites_algorithm_and_private_tool
(self) :
142
alg = self.
_makeAlg
()
143
substituteComponentProperties (alg, self.
SUBS
)
144
145
# algorithm-level properties
146
self.assertEqual (alg.particles,
'AnaJets_%SYS%'
)
147
self.assertEqual (alg.preselection,
'preselect_STEP3,as_char'
)
148
self.assertEqual (alg.selectionDecoration,
'pass_AnaJets_STEP3,as_char'
)
149
150
# private-tool vector<string> property
151
self.assertEqual (list (alg.selectionTool.selectionFlags),
152
[
'AnaJets.flag'
,
153
'MyAnaJets_STEP3.flag'
,
154
'unrelated'
])
155
156
def
test_substitution_is_idempotent
(self) :
157
alg = self.
_makeAlg
()
158
substituteComponentProperties (alg, self.
SUBS
)
159
before_particles = alg.particles
160
before_flags = list (alg.selectionTool.selectionFlags)
161
substituteComponentProperties (alg, self.
SUBS
)
162
self.assertEqual (alg.particles, before_particles)
163
self.assertEqual (list (alg.selectionTool.selectionFlags), before_flags)
164
165
def
test_no_matching_substitution_leaves_properties_unchanged
(self) :
166
alg = self.
_makeAlg
()
167
before_particles = alg.particles
168
before_preselection = alg.preselection
169
before_decoration = alg.selectionDecoration
170
before_flags = list (alg.selectionTool.selectionFlags)
171
substituteComponentProperties (alg, [(
'NonExistentContainer'
,
'Foo'
)])
172
self.assertEqual (alg.particles, before_particles)
173
self.assertEqual (alg.preselection, before_preselection)
174
self.assertEqual (alg.selectionDecoration, before_decoration)
175
self.assertEqual (list (alg.selectionTool.selectionFlags), before_flags)
176
177
def
test_empty_substitutions_leaves_properties_unchanged
(self) :
178
alg = self.
_makeAlg
()
179
before_particles = alg.particles
180
before_flags = list (alg.selectionTool.selectionFlags)
181
substituteComponentProperties (alg, [])
182
self.assertEqual (alg.particles, before_particles)
183
self.assertEqual (list (alg.selectionTool.selectionFlags), before_flags)
184
185
186
if
__name__ ==
'__main__'
:
187
unittest.main()
python.ConfigPropertySubstitution_unitTest.TestSubstituteComponentProperties
Definition
ConfigPropertySubstitution_unitTest.py:118
python.ConfigPropertySubstitution_unitTest.TestSubstituteComponentProperties._makeAlg
_makeAlg(self)
Definition
ConfigPropertySubstitution_unitTest.py:125
python.ConfigPropertySubstitution_unitTest.TestSubstituteComponentProperties.test_substitution_is_idempotent
test_substitution_is_idempotent(self)
Definition
ConfigPropertySubstitution_unitTest.py:156
python.ConfigPropertySubstitution_unitTest.TestSubstituteComponentProperties.test_no_matching_substitution_leaves_properties_unchanged
test_no_matching_substitution_leaves_properties_unchanged(self)
Definition
ConfigPropertySubstitution_unitTest.py:165
python.ConfigPropertySubstitution_unitTest.TestSubstituteComponentProperties.test_substitution_rewrites_algorithm_and_private_tool
test_substitution_rewrites_algorithm_and_private_tool(self)
Definition
ConfigPropertySubstitution_unitTest.py:141
python.ConfigPropertySubstitution_unitTest.TestSubstituteComponentProperties.test_empty_substitutions_leaves_properties_unchanged
test_empty_substitutions_leaves_properties_unchanged(self)
Definition
ConfigPropertySubstitution_unitTest.py:177
python.ConfigPropertySubstitution_unitTest.TestSubstituteComponentProperties.SUBS
list SUBS
Definition
ConfigPropertySubstitution_unitTest.py:123
python.ConfigPropertySubstitution_unitTest.TestSubstituteValue
Definition
ConfigPropertySubstitution_unitTest.py:29
python.ConfigPropertySubstitution_unitTest.TestSubstituteValue.test_list_recurses
test_list_recurses(self)
Definition
ConfigPropertySubstitution_unitTest.py:76
python.ConfigPropertySubstitution_unitTest.TestSubstituteValue.test_empty_substitutions_is_identity
test_empty_substitutions_is_identity(self)
Definition
ConfigPropertySubstitution_unitTest.py:113
python.ConfigPropertySubstitution_unitTest.TestSubstituteValue.test_dict_recurses_on_keys_and_values
test_dict_recurses_on_keys_and_values(self)
Definition
ConfigPropertySubstitution_unitTest.py:82
python.ConfigPropertySubstitution_unitTest.TestSubstituteValue.test_nested_dict_with_list
test_nested_dict_with_list(self)
Definition
ConfigPropertySubstitution_unitTest.py:100
python.ConfigPropertySubstitution_unitTest.TestSubstituteValue.test_set_recurses
test_set_recurses(self)
Definition
ConfigPropertySubstitution_unitTest.py:90
python.ConfigPropertySubstitution_unitTest.TestSubstituteValue.test_string_with_suffix
test_string_with_suffix(self)
Definition
ConfigPropertySubstitution_unitTest.py:41
python.ConfigPropertySubstitution_unitTest.TestSubstituteValue.test_anchored_inside_expression_with_trap
test_anchored_inside_expression_with_trap(self)
Definition
ConfigPropertySubstitution_unitTest.py:64
python.ConfigPropertySubstitution_unitTest.TestSubstituteValue.test_anchored_inside_expression
test_anchored_inside_expression(self)
Definition
ConfigPropertySubstitution_unitTest.py:57
python.ConfigPropertySubstitution_unitTest.TestSubstituteValue.test_plain_string_match
test_plain_string_match(self)
Definition
ConfigPropertySubstitution_unitTest.py:34
python.ConfigPropertySubstitution_unitTest.TestSubstituteValue.SUBS
list SUBS
Definition
ConfigPropertySubstitution_unitTest.py:32
python.ConfigPropertySubstitution_unitTest.TestSubstituteValue.test_plain_string_no_match
test_plain_string_no_match(self)
Definition
ConfigPropertySubstitution_unitTest.py:37
python.ConfigPropertySubstitution_unitTest.TestSubstituteValue.test_multiple_substitutions_applied_in_order
test_multiple_substitutions_applied_in_order(self)
Definition
ConfigPropertySubstitution_unitTest.py:70
python.ConfigPropertySubstitution_unitTest.TestSubstituteValue.test_tuple_recurses
test_tuple_recurses(self)
Definition
ConfigPropertySubstitution_unitTest.py:95
python.ConfigPropertySubstitution_unitTest.TestSubstituteValue.test_string_with_trailing_dot
test_string_with_trailing_dot(self)
Definition
ConfigPropertySubstitution_unitTest.py:47
python.ConfigPropertySubstitution_unitTest.TestSubstituteValue.test_anchored_boundary_left
test_anchored_boundary_left(self)
Definition
ConfigPropertySubstitution_unitTest.py:51
python.ConfigPropertySubstitution_unitTest.TestSubstituteValue.test_non_string_scalars_unchanged
test_non_string_scalars_unchanged(self)
Definition
ConfigPropertySubstitution_unitTest.py:107
Generated on
for ATLAS Offline Software by
1.17.0