3 # WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
7 # Thomas Nagy, 2005-2016 (ita)
11 ConfigSet: a special dict
13 The values put in :py:class:`ConfigSet` must be serializable (dicts, lists, strings)
17 from waflib import Logs, Utils
18 re_imp = re.compile('^(#)*?([^#=]*?)\ =\ (.*?)$', re.M)
20 class ConfigSet(object):
22 A copy-on-write dict with human-readable serialized format. The serialization format
23 is human-readable (python-like) and performed by using eval() and repr().
24 For high performance prefer pickle. Do not store functions as they are not serializable.
26 The values can be accessed by attributes or by keys::
28 from waflib.ConfigSet import ConfigSet
33 __slots__ = ('table', 'parent')
34 def __init__(self, filename=None):
37 Internal dict holding the object values
44 def __contains__(self, key):
46 Enables the *in* syntax::
51 if key in self.table: return True
52 try: return self.parent.__contains__(key)
53 except AttributeError: return False # parent may not exist
60 keys.update(cur.table.keys())
61 cur = getattr(cur, 'parent', None)
67 return iter(self.keys())
70 """Text representation of the ConfigSet (for debugging purposes)"""
71 return "\n".join(["%r %r" % (x, self.__getitem__(x)) for x in self.keys()])
73 def __getitem__(self, key):
75 Dictionary interface: get value from key::
83 x = self.table.get(key)
87 except AttributeError:
90 def __setitem__(self, key, value):
92 Dictionary interface: set value for key
94 self.table[key] = value
96 def __delitem__(self, key):
98 Dictionary interface: mark the key as missing
102 def __getattr__(self, name):
104 Attribute access provided for convenience. The following forms are equivalent::
110 if name in self.__slots__:
111 return object.__getattr__(self, name)
115 def __setattr__(self, name, value):
117 Attribute access provided for convenience. The following forms are equivalent::
123 if name in self.__slots__:
124 object.__setattr__(self, name, value)
128 def __delattr__(self, name):
130 Attribute access provided for convenience. The following forms are equivalent::
136 if name in self.__slots__:
137 object.__delattr__(self, name)
143 Returns a new ConfigSet deriving from self. The copy returned
144 will be a shallow copy::
146 from waflib.ConfigSet import ConfigSet
148 env.append_value('CFLAGS', ['-O2'])
150 child.CFLAGS.append('test') # warning! this will modify 'env'
151 child.CFLAGS = ['-O3'] # new list, ok
152 child.append_value('CFLAGS', ['-O3']) # ok
154 Use :py:func:`ConfigSet.detach` to detach the child from the parent.
162 Detaches this instance from its parent (if present)
164 Modifying the parent :py:class:`ConfigSet` will not change the current object
165 Modifying this :py:class:`ConfigSet` will not modify the parent one.
167 tbl = self.get_merged_dict()
169 delattr(self, 'parent')
170 except AttributeError:
175 tbl[x] = copy.deepcopy(tbl[x])
179 def get_flat(self, key):
181 Returns a value as a string. If the input is a list, the value returned is space-separated.
183 :param key: key to use
187 if isinstance(s, str): return s
190 def _get_list_value_for_modification(self, key):
192 Returns a list value for further modification.
194 The list may be modified inplace and there is no need to do this afterwards::
196 self.table[var] = value
199 value = self.table[key]
202 value = self.parent[key]
203 except AttributeError:
206 if isinstance(value, list):
211 self.table[key] = value
213 if not isinstance(value, list):
214 self.table[key] = value = [value]
217 def append_value(self, var, val):
219 Appends a value to the specified config key::
222 bld.env.append_value('CFLAGS', ['-O2'])
224 The value must be a list or a tuple
226 if isinstance(val, str): # if there were string everywhere we could optimize this
228 current_value = self._get_list_value_for_modification(var)
229 current_value.extend(val)
231 def prepend_value(self, var, val):
233 Prepends a value to the specified item::
236 conf.env.prepend_value('CFLAGS', ['-O2'])
238 The value must be a list or a tuple
240 if isinstance(val, str):
242 self.table[var] = val + self._get_list_value_for_modification(var)
244 def append_unique(self, var, val):
246 Appends a value to the specified item only if it's not already present::
249 bld.env.append_unique('CFLAGS', ['-O2', '-g'])
251 The value must be a list or a tuple
253 if isinstance(val, str):
255 current_value = self._get_list_value_for_modification(var)
258 if x not in current_value:
259 current_value.append(x)
261 def get_merged_dict(self):
263 Computes the merged dictionary from the fusion of self and all its parent
265 :rtype: a ConfigSet object
270 table_list.insert(0, env.table)
271 try: env = env.parent
272 except AttributeError: break
274 for table in table_list:
275 merged_table.update(table)
278 def store(self, filename):
280 Serializes the :py:class:`ConfigSet` data to a file. See :py:meth:`ConfigSet.load` for reading such files.
282 :param filename: file to use
283 :type filename: string
286 os.makedirs(os.path.split(filename)[0])
291 merged_table = self.get_merged_dict()
292 keys = list(merged_table.keys())
301 if k != 'undo_stack':
302 buf.append('%s = %s\n' % (k, fun(merged_table[k])))
303 Utils.writef(filename, ''.join(buf))
305 def load(self, filename):
307 Restores contents from a file (current values are not cleared). Files are written using :py:meth:`ConfigSet.store`.
309 :param filename: file to use
310 :type filename: string
313 code = Utils.readf(filename, m='rU')
314 for m in re_imp.finditer(code):
316 tbl[g(2)] = eval(g(3))
317 Logs.debug('env: %s', self.table)
321 Dictionary interface: replace values with the ones from another dict
323 :param d: object to use the value from
324 :type d: dict-like object
330 Stores the object state to provide transactionality semantics::
335 env.append_value('CFLAGS', '-O3')
336 call_some_method(env)
340 The history is kept in a stack, and is lost during the serialization by :py:meth:`ConfigSet.store`
343 tbl = self.table = self.table.copy()
345 tbl[x] = copy.deepcopy(tbl[x])
346 self.undo_stack = self.undo_stack + [orig]
350 Commits transactional changes. See :py:meth:`ConfigSet.stash`
352 self.undo_stack.pop(-1)
356 Reverts the object to a previous state. See :py:meth:`ConfigSet.stash`
358 self.table = self.undo_stack.pop(-1)