ATLAS Offline Software
Loading...
Searching...
No Matches
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
21import unittest
22
23from AnalysisAlgorithmsConfig.ConfigPropertySubstitution import (
24 substituteComponentProperties,
25 substituteValue,
26)
27
28
29class TestSubstituteValue (unittest.TestCase) :
30 """Pure tests of `substituteValue` — no configurables involved."""
31
32 SUBS = [('Jets_STEP3', 'Jets')]
33
35 self.assertEqual (substituteValue ('Jets_STEP3', self.SUBS), 'Jets')
36
38 self.assertEqual (substituteValue ('Electrons_STEP1', self.SUBS),
39 'Electrons_STEP1')
40
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
48 self.assertEqual (substituteValue ('Jets_STEP3.flag', self.SUBS),
49 'Jets.flag')
50
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
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
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
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
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
96 result = substituteValue (('Jets_STEP3', 'MyJets_STEP3'), self.SUBS)
97 self.assertEqual (result, ('Jets', 'MyJets_STEP3'))
98 self.assertIsInstance (result, tuple)
99
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
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
114 self.assertEqual (substituteValue ('Jets_STEP3', []), 'Jets_STEP3')
115 self.assertEqual (substituteValue (['Jets_STEP3'], []), ['Jets_STEP3'])
116
117
118class 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
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
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
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
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
186if __name__ == '__main__' :
187 unittest.main()