22 """Module which defines ConfigOverrides class and related methods.
25 __all__ = [
"ConfigOverrides"]
28 from operator
import attrgetter
35 OverrideTypes = Enum(
"OverrideTypes",
"Value File Python Instrument")
39 """An expression parser that will be used to transform configuration
40 strings supplied from the command line or a pipeline into a python
43 This is roughly equivalent to ast.literal_parser, but with the ability to
44 transform strings that are valid variable names into the value associated
45 with the name. Variables that should be considered valid are supplied to
46 the constructor as a dictionary that maps a string to its corresponding
49 This class in an internal implementation detail, and should not be exposed
54 namespace : `dict` of `str` to variable
55 This is a mapping of strings corresponding to variable names, to the
56 object that is associated with that name
63 """This method gets called when the parser has determined a node
64 corresponds to a variable name.
75 """This method is visited if the node is a list. Constructs a list out
78 return [self.visit(elm)
for elm
in node.elts]
81 """This method is visited if the node is a tuple. Constructs a list out
82 of the sub nodes, and then turns it into a tuple.
87 """This method is visited if the node is a constant
92 """This method is visited if the node is a dict. It builds a dict out
93 of the component nodes.
95 return {self.visit(key): self.visit(value)
for key, value
in zip(node.keys, node.values)}
98 """This method is visited if the node is a set. It builds a set out
99 of the component nodes.
101 return {self.visit(el)
for el
in node.elts}
104 """This method is visited if the node is a unary operator. Currently
105 The only operator we support is the negative (-) operator, all others
106 are passed to generic_visit method.
108 if isinstance(node.op, ast.USub):
109 value = self.visit(node.operand)
114 """This method is called for all other node types. It will just raise
115 a value error, because this is a type of expression that we do not
118 raise ValueError(
"Unable to parse string into literal expression")
122 """Defines a set of overrides to be applied to a task config.
124 Overrides for task configuration need to be applied by activator when
125 creating task instances. This class represents an ordered set of such
126 overrides which activator receives from some source (e.g. command line
127 or some other configuration).
131 addFileOverride(filename)
132 Add overrides from a specified file.
133 addValueOverride(field, value)
134 Add override for a specific field.
136 Apply all overrides to a `config` instance.
140 Serialization support for this class may be needed, will add later if
148 """Add overrides from a specified file.
153 Path to the override file.
158 """Add override for a specific field.
160 This method is not very type-safe as it is designed to support
161 use cases where input is given as string, e.g. command line
162 activators. If `value` has a string type and setting of the field
163 fails with `TypeError` the we'll attempt `eval()` the value and
164 set the field with that value instead.
169 Fully-qualified field name.
171 Value to be given to a filed.
176 """Add Overrides by running a snippit of python code against a config.
181 A string which is valid python code to be executed. This is done
182 with config as the only local accessible value.
187 """Apply any overrides that an instrument has for a task
192 A string containing the fully qualified name of an instrument from
193 which configs should be loaded and applied
195 The _DefaultName of a task associated with a config, used to look
196 up overrides from the instrument.
198 instrument_lib =
doImport(instrument)()
199 self.
_overrides_overrides.
append((OverrideTypes.Instrument, (instrument_lib, task_name)))
201 def _parser(self, value, configParser):
203 value = configParser.visit(ast.parse(value, mode=
'eval').body)
214 """Apply all overrides to a task configuration object.
218 config : `pex.Config`
222 `Exception` is raised if operations on configuration object fail.
229 mod = inspect.getmodule(config)
230 vars.update({k: v
for k, v
in mod.__dict__.items()
if not k.startswith(
"__")})
232 vars[
'config'] = config
237 for otype, override
in self.
_overrides_overrides:
238 if otype
is OverrideTypes.File:
239 config.load(override)
240 elif otype
is OverrideTypes.Value:
241 field, value = override
242 if isinstance(value, str):
243 value = self.
_parser_parser(value, configParser)
250 if isinstance(value, dict):
252 for k, v
in value.items():
253 if isinstance(v, str):
254 new[k] = self.
_parser_parser(v, configParser)
258 elif isinstance(value, list):
261 if isinstance(v, str):
262 new.append(self.
_parser_parser(v, configParser))
269 parent, *child = field.rsplit(
".", maxsplit=1)
274 finalField = child[0]
275 tmpConfig = attrgetter(parent)(config)
282 setattr(tmpConfig, finalField, value)
284 elif otype
is OverrideTypes.Python:
293 exec(override,
None, vars)
294 elif otype
is OverrideTypes.Instrument:
295 instrument, name = override
296 instrument.applyConfigOverrides(name, config)
def __init__(self, namespace)
def visit_Set(self, node)
def visit_Constant(self, node)
def generic_visit(self, node)
def visit_Dict(self, node)
def visit_Tuple(self, node)
def visit_Name(self, node)
def visit_List(self, node)
def visit_UnaryOp(self, node)
def addPythonOverride(self, str python_snippet)
def addInstrumentOverride(self, str instrument, str task_name)
def addFileOverride(self, filename)
def applyTo(self, config)
def addValueOverride(self, field, value)
def _parser(self, value, configParser)
std::shared_ptr< FrameSet > append(FrameSet const &first, FrameSet const &second)
Construct a FrameSet that performs two transformations in series.