1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)# found in the LICENSE file.
4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)"""Configuration variable management for the cr tool.
6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
7f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)This holds the classes that support the hierarchical variable management used
8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)in the cr tool to provide all the command configuration controls.
9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)"""
10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import string
12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import cr.visitor
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)_PARSE_CONSTANT_VALUES = [None, True, False]
16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)_PARSE_CONSTANTS = dict((str(value), value) for value in _PARSE_CONSTANT_VALUES)
17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)# GLOBALS is the singleton used to tie static global configuration objects
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)# together.
20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)GLOBALS = []
21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class _MissingToErrorFormatter(string.Formatter):
24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  """A string formatter used in value resolve.
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  The main extra it adds is a new conversion specifier 'e' that throws a
27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  KeyError if it could not find the value.
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  This allows a string value to use {A_KEY!e} to indicate that it is a
29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  formatting error if A_KEY is not present.
30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  """
31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def convert_field(self, value, conversion):
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if conversion == 'e':
34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      result = str(value)
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if not result:
36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        raise KeyError('unknown')
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return result
38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return super(_MissingToErrorFormatter, self).convert_field(
39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        value, conversion)
40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class _Tracer(object):
43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  """Traces variable lookups.
44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  This adds a hook to a config object, and uses it to track all variable
46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  lookups that happen and add them to a trail. When done, it removes the hook
47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  again. This is used to provide debugging information about what variables are
48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  used in an operation.
49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  """
50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def __init__(self, config):
52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.config = config
53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.trail = []
54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def __enter__(self):
56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.config.fixup_hooks.append(self._Trace)
57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return self
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def __exit__(self, *_):
60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.config.fixup_hooks.remove(self._Trace)
61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.config.trail = self.trail
62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return False
63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def _Trace(self, _, key, value):
65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.trail.append((key, value))
66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return value
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
69010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)class Config(cr.visitor.Node, cr.loader.AutoExport):
70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  """The main variable holding class.
71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  This holds a set of unresolved key value pairs, and the set of child Config
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  objects that should be referenced when looking up a key.
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  Key search is one in a pre-order traversal, and new children are prepended.
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  This means parents override children, and the most recently added child
76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  overrides the rest.
77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  Values can be simple python types, callable dynamic values, or strings.
79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  If the value is a string, it is assumed to be a standard python format string
80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  where the root config object is used to resolve the keys. This allows values
81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  to refer to variables that are overriden in another part of the hierarchy.
82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  """
83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  @classmethod
85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def From(cls, *args, **kwargs):
86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    """Builds an unnamed config object from a set of key,value args."""
87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return Config('??').Apply(args, kwargs)
88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  @classmethod
90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def If(cls, condition, true_value, false_value=''):
91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    """Returns a config value that selects a value based on the condition.
92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Args:
94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        condition: The variable name to select a value on.
95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        true_value: The value to use if the variable is True.
96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        false_value: The value to use if the resolved variable is False.
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Returns:
98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        A dynamic value.
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    """
100effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    def Resolve(base):
101effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      test = base.Get(condition)
102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if test:
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        value = true_value
104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      else:
105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        value = false_value
106effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return base.Substitute(value)
107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return Resolve
108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  @classmethod
110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def Optional(cls, value, alternate=''):
111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    """Returns a dynamic value that defaults to an alternate.
112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Args:
114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        value: The main value to resolve.
115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        alternate: The value to use if the main value does not resolve.
116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Returns:
117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        value if it resolves, alternate otherwise.
118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    """
119effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    def Resolve(base):
120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      try:
121effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        return base.Substitute(value)
122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      except KeyError:
123effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        return base.Substitute(alternate)
124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return Resolve
125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def __init__(self, name='--', literal=False, export=None, enabled=True):
127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    super(Config, self).__init__(name=name, enabled=enabled, export=export)
128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self._literal = literal
129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self._formatter = _MissingToErrorFormatter()
130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.fixup_hooks = []
131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.trail = []
132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  @property
134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def literal(self):
135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return self._literal
136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def Substitute(self, value):
138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return self._formatter.vformat(str(value), (), self)
139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def Resolve(self, visitor, key, value):
141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    """Resolves a value to it's final form.
142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Raw values can be callable, simple values, or contain format strings.
144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Args:
145010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      visitor: The visitor asking to resolve a value.
146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      key: The key being visited.
147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      value: The unresolved value associated with the key.
148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Returns:
149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      the fully resolved value.
150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    """
151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    error = None
152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if callable(value):
153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      value = value(self)
154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    # Using existence of value.swapcase as a proxy for is a string
155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    elif hasattr(value, 'swapcase'):
156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if not visitor.current_node.literal:
157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        try:
158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          value = self.Substitute(value)
159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        except KeyError as e:
160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          error = e
161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return self.Fixup(key, value), error
162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def Fixup(self, key, value):
164f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    for hook in self.fixup_hooks:
165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      value = hook(self, key, value)
166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return value
167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
168010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  def Missing(self, key):
169010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    for hook in self.fixup_hooks:
170010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      hook(self, key, None)
171010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    raise KeyError(key)
172010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  @staticmethod
174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def ParseValue(value):
175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    """Converts a string to a value.
176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Takes a string from something like an environment variable, and tries to
178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    build an internal typed value. Recognizes Null, booleans, and numbers as
179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    special.
180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Args:
181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        value: The the string value to interpret.
182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Returns:
183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        the parsed form of the value.
184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    """
185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if value in _PARSE_CONSTANTS:
186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return _PARSE_CONSTANTS[value]
187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    try:
188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return int(value)
189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    except ValueError:
190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      pass
191f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    try:
192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return float(value)
193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    except ValueError:
194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      pass
195f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return value
196f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
197f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def _Set(self, key, value):
198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    # early out if the value did not change, so we don't call change callbacks
199f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if value == self._values.get(key, None):
200f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return
201f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self._values[key] = value
202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.NotifyChanged()
203f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return self
204f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def ApplyMap(self, arg):
206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    for key, value in arg.items():
207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      self._Set(key, value)
208f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return self
209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def Apply(self, args, kwargs):
211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    """Bulk set variables from arguments.
212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Intended for internal use by the Set and From methods.
214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Args:
215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        args: must be either a dict or something that can build a dict.
216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        kwargs: must be a dict.
217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Returns:
218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        self for easy chaining.
219f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    """
220f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if len(args) == 1:
221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      arg = args[0]
222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if isinstance(arg, dict):
223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        self.ApplyMap(arg)
224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      else:
225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        self.ApplyMap(dict(arg))
226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    elif len(args) > 1:
227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      self.ApplyMap(dict(args))
228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.ApplyMap(kwargs)
229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return self
230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
231f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def Set(self, *args, **kwargs):
232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return self.Apply(args, kwargs)
233f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
234f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def Trace(self):
235f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return _Tracer(self)
236f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
237f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def __getitem__(self, key):
238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return self.Get(key)
239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def __setitem__(self, key, value):
241f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self._Set(key, value)
242a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
243a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  def __contains__(self, key):
244a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return self.Find(key) is not None
245