9 """Standalone Analysis Algorithm Configuration
11 This class is used to describe the configuration of an analysis algorithm
12 (a C++ class inheriting from EL::AnaAlgorithm) in Python. It behaves
13 similar to an Athena configurable, but is implemented in a much simpler
16 An example of using it in configuring an EventLoop job could look like:
20 from AnaAlgorithm.AnaAlgorithmConfig import AnaAlgorithmConfig
21 alg = AnaAlgorithmConfig( "EL::UnitTestAlg2/TestAlg",
23 alg.string_property = "Foo"
26 Note that the python code doesn't know what properties can actually be set
27 on any given C++ algorithm. Any mistake made in the Python configuration
28 (apart from syntax errors) is only discovered while initialising the
37 """Constructor for an algorithm configuration object
40 typeAndName -- The type/instance name of the algorithm
42 Note that you can pass (initial) properties to the constructor like:
44 alg = AnaAlgorithmConfig( "EL::UnitTestAlg2/TestAlg",
50 super( AnaAlgorithmConfig, self ).
__init__()
51 self.setTypeAndName( typeAndName )
57 for key, value
in kwargs.items():
59 self.
_props[ key ] = copy.deepcopy( value )
65 """Get the instance name of the algorithm
67 This is for compatibility with the getName() function of Athena
74 """Get the type name of the algorithm
76 This is for compatibility with the getType() function of Athena
83 """Get a previously set property value from the configuration
85 This function allows us to retrieve the value of a property that was
86 already set for the algorithm, to possibly use it in some configuration
87 decisions in the Python code itself.
90 name -- The name of the property
94 if not name
in self.
_props:
95 raise AttributeError(
'Property \'%s\' was not set on \'%s/%s\'' %
96 ( name, self.type(), self.name() ) )
102 """Set an algorithm property on an existing configuration object
104 This function allows us to set/override properties on an algorithm
105 configuration object. Allowing for the following syntax:
109 alg.FloatProperty = 3.141592
110 alg.StringProperty = "Foo"
113 key -- The key/name of the property
114 value -- The value to set for the property
119 return super( AnaAlgorithmConfig, self ).
__setattr__( key, value )
122 super( AnaAlgorithmConfig,
124 self.
_props[ key ] = copy.deepcopy( value )
128 """Check for equality with another object
130 The implementation of this is very simple. We only check that the type
131 and the name of the algorithms would match.
135 if not isinstance( other, AnaAlgorithmConfig ):
139 return ( ( self.type() == other.type() )
and
140 ( self.name() == other.name() ) )
143 """Check for an inequality with another object
145 This is just defined to make the '!=' operator of Python behave
146 consistently with the '==' operator for such objects.
148 return not self.
__eq__( other )
151 """Print the algorithm configuration in a user friendly way
153 This is just to help with debugging configurations, allowing
154 the user to get a nice printout of their job configuration.
158 if self.isPublicTool():
159 name =
'Public Tool %s/%s' % ( self.type(), self.name() )
161 name =
'Algorithm %s/%s' % ( self.type(), self.name() )
163 result = AnaAlgorithmConfig._printHeader( name )
166 if isinstance( value, str ):
167 printedValue =
"'%s'" % value
171 result +=
"|- %s: %s\n" % ( key,
indentBy( printedValue,
"| " ) )
173 result += AnaAlgorithmConfig._printFooter( name )
177 """Create a private tool for the algorithm
179 This function is used in 'standalone' mode to declare a private tool
180 for the algorithm, or a private tool for an already declared private
184 config.addPrivateTool( 'tool1', 'ToolType1' )
185 config.addPrivateTool( 'tool1.tool2', 'ToolType2' )
188 name -- The full name of the private tool
189 type -- The C++ type of the private tool
197 toolNames = name.split(
'.' )
201 for tname
in toolNames[ 0 : -1 ]:
202 component = getattr( component, tname )
206 if hasattr( component, toolNames[ -1 ] ):
207 raise RuntimeError(
"Tool with name '%s' already exists" % name )
215 self.createPrivateTool( name, type ).
ignore()
220 """Create a private tool in an array for the algorithm
222 This function is used in 'standalone' mode to declare a
223 private tool in a tool array for the algorithm, or a private
224 tool in a tool array for an already declared private tool.
227 tool = config.addPrivateToolInArray( 'tool1', 'ToolType1' )
228 tool = config.addPrivateToolInArray( 'tool1.tool2', 'ToolType2' )
231 name -- The full name of the private tool
232 type -- The C++ type of the private tool
240 toolNames = name.split(
'.' )
244 for tname
in toolNames[ 0 : -1 ]:
245 component = getattr( component, tname )
249 actualName = self.createPrivateToolInArray( name, type )
253 actualToolNames = actualName.split(
'.' )
257 component._props[ actualToolNames[ -1 ] ] = config
262 """Produce a nice header when printing the configuration
264 This function is used for printing the header of both algorithms
268 indentString -- String used as indentation
269 title -- The title of the algorithm/tool
272 preLength = AnaAlgorithmConfig.printHeaderPre
273 postLength = AnaAlgorithmConfig.printHeaderWidth - 3 - preLength - \
275 return '/%s %s %s' % ( preLength *
'*', title, postLength *
'*' )
279 """Produce a nice footer when printing the configuration
281 This function is used for printing the footer of both algorithms
285 indentString -- String used as indentation
286 title -- The title of the algorithm/tool
289 preLength = AnaAlgorithmConfig.printHeaderPre
290 postLength = AnaAlgorithmConfig.printHeaderWidth - 12 - preLength - \
292 return '\\%s (End of %s) %s' % ( preLength *
'-', title,
299 """Standalone Private Tool Configuration
301 This class is used to mimic the behaviour of Athena tool configurable
302 classes. To be able to set the properties of private tools used by
303 dual-use algorithms in a way that's valid for both Athena and EventLoop.
307 """Constructor for an private tool configuration object
318 """Get a previously set property value from the configuration
320 This function allows us to retrieve the value of a tool property that
321 was already set for an algorithm's private tool, to possibly use it in
322 some configuration decisions in the Python code itself.
325 name -- The name of the property
329 if not name
in self.
_props:
330 raise AttributeError(
'Property "%s" was not set on "%s/%s.%s"' %
335 return self.
_props[ name ]
338 """Set a tool property on an existing configuration object
340 This function allows us to set/override properties on a private tool
341 of an algorithm configuration object. Allowing for the following syntax:
344 alg.Tool.IntProperty = 66
345 alg.Tool.FloatProperty = 3.141592
346 alg.Tool.StringProperty = "Foo"
349 key -- The key/name of the property
350 value -- The value to set for the property
355 return super( PrivateToolConfig, self ).
__setattr__( key, value )
358 fullName = self.
_prefix +
"." + key
361 self.
_algorithm.setPropertyFromString( fullName,
363 self.
_props[ key ] = copy.deepcopy( value )
367 """Print the private tool configuration in a user friendly way
369 This is just to help with debugging configurations, allowing
370 the user to get a nice printout of their job configuration.
373 name =
'Private Tool %s/%s' % ( self.
_type, self.
_prefix )
375 result += AnaAlgorithmConfig._printHeader( name )
378 if isinstance( value, str ):
379 printedValue =
"'%s'" % value
383 result +=
"|- %s: %s\n" % ( key,
indentBy( printedValue,
"| " ) )
385 result += AnaAlgorithmConfig._printFooter( name )
392 """Helper function producing a string property value"""
394 stringValue =
str( value )
395 if isinstance( value, bool ):
396 stringValue =
str(
int( value ) )
402 """Helper function used in the configuration printout"""
404 stringValue =
str( propValue )
406 for stringLine
in stringValue.split(
'\n' ):
408 result +=
"\n" + indent
426 self.assertEqual( config1.type(),
"TypeName" )
427 self.assertEqual( config1.name(),
"TypeName" )
429 self.assertEqual( config2.type(),
"NS::SomeType" )
430 self.assertEqual( config2.name(),
"NS::SomeType" )
437 self.assertEqual( config1.type(),
"TypeName" )
438 self.assertEqual( config1.name(),
"InstanceName" )
440 self.assertEqual( config2.type(),
"NS::SomeType" )
441 self.assertEqual( config2.name(),
"Instance" )
454 self.
config.Prop1 =
"Value1"
455 self.
config.Prop2 = [
"Value2" ]
456 self.assertEqual( self.
config.Prop1,
"Value1" )
457 self.assertEqual( self.
config.Prop2, [
"Value2" ] )
458 self.assertNotEqual( self.
config.Prop1,
"Foo" )
459 self.assertNotEqual( self.
config.Prop2,
"Value2" )
464 with self.assertRaises( AttributeError ):
480 self.
config.Tool1.Prop1 =
"Value1"
481 self.
config.Tool1.Prop2 = [ 1, 2, 3 ]
482 self.assertEqual( self.
config.Tool1.Prop1,
"Value1" )
483 self.assertEqual( self.
config.Tool1.Prop2, [ 1, 2, 3 ] )
489 tool.Prop1 =
"Value1"
490 tool.Prop2 = [ 1, 2, 3 ]
491 self.assertEqual( tool.Prop1,
"Value1" )
492 self.assertEqual( tool.Prop2, [ 1, 2, 3 ] )
499 self.
config.Tool1.Tool2.Prop3 =
"Foo"
500 self.
config.Tool1.Tool2.Prop4 = [
"Bar" ]
501 self.assertEqual( self.
config.Tool1.Tool2.Prop3,
"Foo" )
502 self.assertEqual( self.
config.Tool1.Tool2.Prop4, [
"Bar" ] )
508 with self.assertRaises( AttributeError ):
509 value = self.
config.Tool1.BadProp
512 with self.assertRaises( AttributeError ):
513 value = self.
config.Tool1.Tool2.BadProp
519 with self.assertRaises( AttributeError ):