6 from AthenaCommon
import CfgMgr, CFElements
7 from AthenaCommon.AlgSequence
import AthSequencer
9 from AthenaCommon.Logging
import logging
10 from AthenaConfiguration.ComponentFactory
import CompFactory, isComponentAccumulatorCfg
11 from AthenaConfiguration.ComponentAccumulator
import ConfigurationError
12 from AthenaConfiguration.Deduplication
import DeduplicationFailed
15 import collections.abc
19 """For indendation of debug output"""
23 """Is old-style Configurable"""
24 return isinstance(c, Configurable)
28 _semanticsHelpers = (GaudiConfig2.semantics._ListHelper,
29 GaudiConfig2.semantics._DictHelper,
30 GaudiConfig2.semantics._SetHelper)
33 """Recursively convert GaudiConfig2 semantics helpers"""
34 if isinstance(value, GaudiConfig2.semantics._ListHelper):
36 if isinstance(value, GaudiConfig2.semantics._DictHelper):
38 if isinstance(value, GaudiConfig2.semantics._SetHelper):
44 """Set properties from src (GaudiConfig2) on dest configurable"""
46 _log = logging.getLogger(
"_setProperties" )
48 for pname, pvalue
in src._properties.items():
49 if dest.__class__.__name__ ==
'AthSequencer' and pname ==
'Members':
52 propType = src._descriptors[pname].cpp_type
53 if "PrivateToolHandleArray" in propType:
56 parent = f
"{src.getName()}.{pname}",
57 propType = propType )
for tool
in pvalue] )
58 _log.debug(
"%sSetting private tool array property %s of %s",
59 indent, pname, dest.name() )
61 elif (
"PrivateToolHandle" in propType
or
62 "GaudiConfig2.Configurables" in propType
or
63 "ServiceHandle" in propType):
65 _log.debug(
"%sSetting property %s of %s",
66 indent, pname, dest.name() )
68 _log.debug(
"%sComponent: %s", indent, pvalue)
71 if pvalue
is not None:
74 parent = f
"{src.getName()}.{pname}",
75 propType = propType ) )
77 setattr( dest, pname, pvalue )
80 if isinstance(pvalue, _semanticsHelpers):
83 _log.debug(
"%sSetting property %s to value %s", indent, pname, pvalue )
86 setattr( dest, pname, pvalue )
90 with ConfigurableCABehavior(target_state=
False):
95 """Merge conf2sequence into currentConfigurableSeq"""
97 sequence = CFElements.findSubSequence( currentConfigurableSeq, conf2Sequence.name )
101 currentConfigurableSeq += sequence
102 _log.debug(
"%sCreated missing AthSequencer %s and added to %s",
103 _indent( indent ), sequence.name(), currentConfigurableSeq.name() )
105 for el
in conf2Sequence.Members:
106 if el.__class__.__name__
in [
"AthSequencer"]:
108 elif el.getGaudiType() ==
"Algorithm":
115 and not ( toadd.name()==
'SGInputLoader' and sequence.name()
not in [
'AthAlgSeq',
'HLTBeginSeq'])
118 _log.debug(
"%sAlgorithm %s and added to the sequence %s",
119 _indent( indent ), el.getFullJobOptName(), sequence.name() )
122 def conf2toConfigurable( comp, indent="", parent="", servicesOfThisCA=[], suppressDupes=False, propType="" ):
124 Method converts from Conf2 ( comp argument ) to old Configurable
125 If the Configurable of the same name exists, the properties merging process is invoked
127 _log = logging.getLogger(
"conf2toConfigurable" )
130 _log.debug(
"%sComponent is already OLD Configurable object %s, no conversion",
131 indent, comp.getName() )
134 if isinstance(comp, str):
135 if comp
and 'ServiceHandle' not in propType:
136 _log.warning(
"%sComponent '%s' in '%s' is of type string, no conversion, "
137 "some properties possibly not set?", indent, comp, parent)
140 if comp.getType() ==
'AthSequencer':
141 _log.debug(
"%sComponent is a sequence %s, attempt to merge",
142 indent, comp.getName())
147 _log.debug(
"%sConverting from GaudiConfig2 object %s type %s, parent %s",
148 indent, comp.getName(), comp.__class__.__name__ , parent)
150 def _alreadyConfigured( comp, parent ):
151 instanceName = comp.getName()
152 for conf
in Configurable.allConfigurables.values():
155 conf_name=conf.name()
160 if conf_name==instanceName:
161 if conf.getParent() == parent:
162 _log.debug(
"%s Matched component: '%s' with parent %s with same from allConfigurables match.",
163 indent, instanceName, parent
if parent
else "[not set]" )
166 _log.debug(
"%sComponent: '%s' had parent %s whilst this allConfigurables match had parent %s.",
167 indent, instanceName, parent
if parent
else "[not set]", conf.getParent() )
170 def _createConf2Object( name ):
171 typename, instanceName = name.split(
"/")
if "/" in name
else (name,name)
172 return CompFactory.getComp( typename.replace(
"__",
"::") )( instanceName )
174 def _configurableToConf2( comp, indent="" ):
175 _log.debug(
"%sConverting Conf2 to Configurable class %s, type %s", indent, comp.getFullName(),
type(comp) )
176 conf2Object = _createConf2Object( comp.getFullName() )
177 _getProperties( comp, conf2Object,
_indent( indent ) )
180 def _getProperties( src, dest, indent="" ):
181 """Read properties on src and set them on dest (GaudiConfig2) configurable"""
182 for prop, value
in src.getProperties().
items():
183 _log.debug(
"%sDealing with class %s property %s value type %s",
184 indent, src.getFullJobOptName(), prop,
type(value) )
185 if "ServiceHandle" in str(
type( value ) ):
186 instance = _alreadyConfigured(value, src.getName())
188 setattr( dest, prop, _configurableToConf2(instance,
_indent(indent)) )
190 if isinstance(value, _semanticsHelpers):
192 setattr( dest, prop, value )
194 def _findConfigurableClass( name ):
195 """Find old-style Configurable class for name"""
197 name = name.replace(
"::",
"__")
200 name=name.replace(
"<",
"_")
201 name=name.replace(
">",
"_")
202 name=name.replace(
", ",
"_")
204 classObj = getattr( CfgMgr, name )
207 raise ConfigurationError(f
"CAtoGlobalWrapper could not find the component of type {name}")
211 def _areSettingsSame( conf1, conf2, indent="",servicesOfThisCA=[] ):
212 """Are the properties the same between old-style conf1 and new-style conf2 instance?"""
213 from AthenaCommon.AppMgr
import ToolSvc
215 _log.debug(
"%sChecking if settings are the same %s (%s) old(new)",
216 indent, conf1.getFullName(), conf2.getFullJobOptName() )
218 if conf1.getType() != conf2.__cpp_type__:
219 raise ConfigurationError(
"Old/new ({} | {}) cpp types are not the same for ({} | {}) !".
format(
220 conf1.getType(), conf2.__cpp_type__,
221 conf1.getFullName(), conf2.getFullJobOptName() ) )
223 alreadySetProperties = conf1.getValuedProperties().
copy()
225 _log.debug(
"%sExisting properties: %s", indent, alreadySetProperties )
226 _log.debug(
"%sNew properties: %s", indent, conf2._properties )
228 for pname, pvalue
in conf2._properties.items():
231 _log.warning(
"%sNew configuration object %s property %s has legacy configuration "
232 "components assigned to it %s. Skipping comparison, no guarantees "
233 "about configuration consistency.",
234 indent, conf2.getName(), pname, pvalue.getName() )
237 propType = conf2._descriptors[pname].cpp_type
238 _log.debug(
"%sComparing type: %s for: %s in: %s", indent, propType, pname, conf1.getFullJobOptName() )
240 if "PrivateToolHandleArray" in propType:
241 toolDict = {_.getName(): _
for _
in alreadySetProperties[pname]}
242 _log.debug(
'Private tool properties? %s', toolDict)
243 newCdict = {_.getName() : _
for _
in pvalue}
244 oldCset =
set(toolDict); newCset =
set(newCdict)
245 _log.debug(
'Private tool property names? %s %s', oldCset, newCset)
246 if (
not (oldCset == newCset) ):
249 _log.debug(
'%s PrivateToolHandleArray %s of %s does not have the same named components',indent, pname, conf1.getFullJobOptName() )
250 _log.debug(
'%s Old (conf1) %s for %s',indent,
sorted(oldCset), conf1.getFullJobOptName())
251 _log.debug(
'%s New (conf2) %s for %s',indent,
sorted(newCset), conf2.getFullJobOptName())
252 _log.debug(
'%s Will try to merge them, but this might go wrong!',indent)
253 for oldC
in oldCset & newCset:
254 _areSettingsSame( toolDict[oldC], newCdict[oldC],
_indent(indent),servicesOfThisCA)
257 for newC
in sorted(newCset-oldCset):
258 className = newCdict[newC].getFullJobOptName().
split(
"/" )[0]
259 _log.debug(
'%s%s not in old config. Will try to create conf1 instance using '
260 'this className: %s, and merge.',indent, newC, className)
261 configurableClass = _findConfigurableClass( className )
264 tmpName = newC + className +
str(len(indent))
265 instance = configurableClass( tmpName )
268 instance._name = newCdict[newC].name
269 if hasattr(instance,
'_jobOptName'):
270 instance._jobOptName = instance._name
272 instance.allConfigurables[instance._name] = instance.allConfigurables.pop(tmpName)
273 instance.configurables[instance._name] = instance.configurables.pop(tmpName)
276 _log.debug(
'%s will now add %s to array.',indent, instance)
279 alreadySetProperties[pname].
append(conf1.getChildren()[-1])
281 elif "PublicToolHandleArray" in propType:
282 toolSet = {_.getName()
for _
in alreadySetProperties[pname]}
283 _log.debug(
'Public tool handle array properties? %s %s', toolSet, pvalue)
286 if isinstance(newC, str):
287 pubtoolclass, pubtoolname = newC.split(
'/')
288 if pubtoolname
not in toolSet:
289 klass = _findConfigurableClass( pubtoolclass )
290 instance =
klass(pubtoolname)
292 alreadySetProperties[pname].
append(instance)
294 _log.warning(
'Not handling actual Configurable2s for public tool merging yet')
297 elif (
"PrivateToolHandle" in propType
or
298 "GaudiConfig2.Configurables" in propType
or
299 "ServiceHandle" in propType):
300 existingVal = getattr(conf1, pname)
301 if isinstance( pvalue, str ):
303 if "ServiceHandle" in propType
and pvalue
in servicesOfThisCA:
304 _log.debug(
"%sThe service %s is part of the CA. Consistency checks will be performed when the service is merged")
307 _log.debug(
"%sThe %s '%s' of GaudiConfig2 component %s.%s is a string, "
308 "skipping deeper checks",
309 indent, propType, pvalue, conf2.name, pname)
311 _log.debug(
"%sThe property value for %s of %s is None. Skipping.", indent, pname, conf2.name )
313 elif str(existingVal) ==
"":
314 className = pvalue.getFullJobOptName().
split(
"/" )[0]
315 pvalueCompName = pvalue.getFullJobOptName().
split(
"/" )[1]
316 _log.debug(
"%sThe existing value for %s of %s is an empty handle. "
317 "Will try to create conf1 instance using this className: %s, and merge.",
318 indent, pname, conf2.name, className )
319 configurableClass = _findConfigurableClass( className )
322 tmpName = pvalueCompName + className +
str(len(indent))
323 instance = configurableClass( tmpName )
325 instance._name = pvalueCompName
326 if hasattr(instance,
'_jobOptName'):
327 instance._jobOptName = instance._name
329 instance.allConfigurables[instance._name] = instance.allConfigurables.pop(tmpName)
330 instance.configurables[instance._name] = instance.configurables.pop(tmpName)
332 setattr(conf1, pname, instance)
333 existingVal = getattr(conf1, pname)
334 _areSettingsSame( existingVal, pvalue, indent,servicesOfThisCA)
336 _log.debug(
"%sSome kind of handle and, object type %s existing %s",
337 indent,
type(pvalue),
type(existingVal) )
338 _areSettingsSame( existingVal, pvalue, indent,servicesOfThisCA)
340 if isinstance(pvalue, _semanticsHelpers):
343 if pname
not in alreadySetProperties:
344 _log.debug(
"%sAdding property: %s for %s", indent, pname, conf2.getName() )
346 setattr(conf1, pname, pvalue)
347 except AttributeError:
348 _log.info(
"%sCould not set attribute. Type of conf1 %s.",indent,
type(conf1) )
351 elif alreadySetProperties[pname] != pvalue:
358 if (isinstance(pvalue, str)
and isinstance(alreadySetProperties[pname], str)):
360 and pvalue.split(
'/')[-1] == alreadySetProperties[pname]):
363 _log.warning(
"%sProperties here are strings and not exactly the same. "
364 "ASSUMING they match types but we cannot check. %s for %s",
365 indent, pname, conf2.getName() )
367 if (
'+' in alreadySetProperties[pname].toStringProperty()
and
368 alreadySetProperties[pname].toStringProperty().
split(
'+')[-1] == pvalue):
371 except AttributeError :
377 _log.debug(
"%sMerging property: %s for new config: %s", indent, pname, conf2.getName() )
379 clone = conf2.getInstance(
"Clone")
380 setattr(clone, pname, alreadySetProperties[pname])
383 getattr(conf2, pname), getattr(clone, pname)) )
384 except (TypeError, ValueError):
385 err_message = f
"Failed merging new config value ({getattr(conf2, pname)}) and old config value ({getattr(clone, pname)}) for the ({pname}) property of {conf1.getFullJobOptName() } ({conf2.getFullJobOptName()}) old (new)."
386 _log.fatal( err_message )
387 raise ConfigurationError(err_message)
389 _log.debug(
"existingConfigurable.name: %s, pname: %s, updatedPropValue: %s",
390 conf1.name(), pname, updatedPropValue )
392 setattr(conf1, pname, updatedPropValue)
394 _log.debug(
"%sInvoked GaudiConf2 semantics to merge the %s and the %s to %s "
395 "for property %s of %s",
396 indent, alreadySetProperties[pname], pvalue, pname,
397 updatedPropValue, existingConfigurable.getFullName())
399 _log.debug(
"%sConf2 Full name: %s ", indent, comp.getFullJobOptName() )
400 existingConfigurable = _alreadyConfigured( comp, parent )
402 if existingConfigurable:
403 _log.debug(
"%sPre-existing configurable %s was found, checking if has the same properties",
404 indent, existingConfigurable.getFullJobOptName() )
405 _areSettingsSame( existingConfigurable, comp, indent, servicesOfThisCA )
406 _log.debug(
"%sPre-existing configurable %s was found to have the same properties",
408 instance = existingConfigurable
if not suppressDupes
else None
411 _log.debug(
"%sExisting Conf1 not found. Creating component configurable %s",
412 indent, comp.getFullJobOptName() )
413 configurableClass = _findConfigurableClass( comp.getFullJobOptName().
split(
"/" )[0] )
414 instance = configurableClass( comp.name )
421 """Execute the cfgFunc CA with the given flags and arguments and run appendCAtoAthena.
422 Return the result of cfgFunc."""
424 raise RuntimeError(
"CAtoGlobalWrapper should not be called in pure CA config")
426 if not callable(cfgFunc):
427 raise TypeError(
"CAtoGlobalWrapper must be called with a configuration-function as parameter")
429 with ConfigurableCABehavior():
430 result = cfgFunc(flags, **kwargs)
431 if isinstance(result, tuple):
440 from AthenaCommon.AppMgr
import (ServiceMgr, ToolSvc, theApp,
441 athCondSeq, athOutSeq, athAlgSeq)
442 _log = logging.getLogger(
"conf2toConfigurable" )
443 _log.debug(
"Merging ComponentAccumulator into global configuration" )
446 servicesOfThisCA=[svc.getFullJobOptName()
for svc
in ca.getServices()]
448 if len( ca.getPublicTools() ) != 0:
449 for comp
in ca.getPublicTools():
450 instance =
conf2toConfigurable( comp, indent=
" ", parent=
"ToolSvc", servicesOfThisCA=servicesOfThisCA )
451 if instance
not in ToolSvc:
454 if len(ca.getServices()) != 0:
455 for comp
in ca.getServices():
457 if instance
not in ServiceMgr:
458 ServiceMgr += instance
459 for svcName
in ca._servicesToCreate:
460 if svcName
not in theApp.CreateSvc:
461 theApp.CreateSvc += [svcName]
463 if len(ca._conditionsAlgs) != 0:
464 for comp
in ca._conditionsAlgs:
466 if instance
not in athCondSeq:
467 athCondSeq += instance
469 if len( ca.getAppProps() ) != 0:
470 for propName, propValue
in ca.getAppProps().
items():
472 if not hasattr(theApp, propName):
473 setattr(theApp, propName, propValue)
475 origPropValue = getattr(theApp, propName)
476 if origPropValue == propValue:
477 _log.info(
"ApplicationMgr property '%s' already set to '%s'.", propName, propValue)
478 elif isinstance(origPropValue, collections.abc.Sequence)
and not isinstance(origPropValue, str):
479 propValue = origPropValue + [el
for el
in propValue
if el
not in origPropValue]
480 _log.info(
"ApplicationMgr property '%s' already set to '%s'. Overwriting with %s",
481 propName, origPropValue, propValue)
482 setattr(theApp, propName, propValue)
484 raise DeduplicationFailed(f
"ApplicationMgr property {propName} set twice: "
485 "{origPropValue} and {propValue}")
487 preconfigured = [athCondSeq,athOutSeq,athAlgSeq]
489 for seq
in ca._allSequences:
491 for pre
in preconfigured:
492 if seq.getName() == pre.getName():
493 _log.debug(
"%sfound sequence %s to have the same name as predefined %s",
494 _indent(), seq.getName(), pre.getName() )
498 if CFElements.findSubSequence( pre, seq.name ):
499 _log.debug(
"%sfound sequence %s in predefined %s",
500 _indent(), seq.getName(), pre.getName() )
506 _log.debug(
"%snot found sequence %s merging it to AthAlgSeq",
_indent(), seq.name )
510 _log.debug(
"Merging of CA to global done" )