Yaco¶
Yaco provides a dict like structure that can be serialized to & from yaml. Yaco objects behave as dictionaries but also allow attribute access (loosely based on this `recipe < http://code.activestate.com/recipes/473786/>`_). Sublevel dictionaries are automatically converted to Yaco objects, allowing sublevel attribute access, for example:
>>> x = Yaco()
>>> x.test = 1
>>> x.sub.test = 2
>>> x.sub.test
2
Note that sub-dictionaries do not need to be initialized. This has as a consequence that requesting uninitialized items automatically return an empty Yaco object (inherited from a dictionary).
Yaco can be found in the Python package index and is also part of the Moa source distribution
Autogenerating keys¶
An important feature (or annoyance) of Yaco is the auto generation of keys that are not present (yet). For example:
>>> x = Yaco()
>>> x.a.b.c.d = 1
>>> assert(x.a.b.c.d == 1)
works - a, b and c are assumed to be Yaco dictionaries and d is give value 1. This makes populating data structures easy.
It might also generate some confusion when querying for keys in the Yaco structure - if a key does not exists, it automatically comes back as an empy dict or Yaco object (renders as {}). This means that if it is easy to check if a certain ‘branch’ of a Yaco datastructure exists:
>>> x = Yaco()
>>> assert (not x.a.b)
but now the following works as well:
>>> assert('a' in x)
>>> assert('b' in x.a )
So, a safe way to test a data structure, without introducing extra branches is:
>>> x = Yaco()
>>> assert(not 'a' in x)
Todo: Need to find a more elegant way of testing without introducing data structures
-
class
Yaco.
PolyYaco
(name='PY', files=[], pattern='*.config', leaf='')¶ A meta object that allows a composite Yaco object to be loaded from any number of different files which are kept as a stack of Yaco objects. If looking for a value, this object will check each of the layers in the stack and return the first value that it comes across.
Changes are only made to the toplevel object.
The goal is to have multiple configuration files, for example in:
/location/to/python/package/etc/config.yaml /etc/APPLICATION.yaml ~/.config/APPLICATION/config.yaml
and have values in the latter file override those in the former. Saving changed values will also be done to the latter, but system and application wide settings can be maintained as well (manually for the time being).
-
load
(leaf, files, pattern)¶
-
-
class
Yaco.
Yaco
(data={}, leaf=None)¶ - Originated from:
- http://code.activestate.com/recipes/473786/
>>> v= Yaco() >>> v.a = 1 >>> assert(v.a == 1) >>> assert(v['a'] == 1) >>> v= Yaco({'a':1}) >>> assert(v.a == 1) >>> assert(v['a'] == 1)
-
get_data
()¶ Prepare & parse data for export
>>> y = Yaco() >>> y.a = 1 >>> y.b = 2 >>> y._c = 3 >>> assert(y._c == 3) >>> d = y.get_data() >>> assert('a' in d) >>> assert('b' in d) >>> assert(not 'c' in d) >>> y._private = ['b'] >>> d = y.get_data() >>> assert('a' in d) >>> assert(not 'b' in d) >>> assert(not '_c' in d)
-
load
(from_file, leaf=None)¶ Load this dict from_file
Note - it can load the file into a leaf, instead of the root of this Yaco structure. Note - the leaf variable is a string, but may contain dots (which are automatically interpreted)
>>> import tempfile >>> tf = tempfile.NamedTemporaryFile(delete=True) >>> tf.close() >>> x = Yaco({'a': [1,2,3, [1,2,3, {'d' : 4}]], ... 'b': 4, 'c': '5', 'uni' : "Aπ"}) >>> x.save(tf.name) >>> y = Yaco() >>> y.load(tf.name) >>> assert(y.a[3][3].d == 4) >>> assert(sys.version_info[0] == 2 or y.uni == "Aπ")
-
pretty
()¶ Return data as a pprint.pformatted string
-
save
(to_file, doNotSave=[])¶
-
simple
()¶ return a simplified representation of this Yaco struct - remove Yaco from the equation - and all object reference. Leave only bool, float, str, lists, tuples and dicts
>>> x = Yaco() >>> x.y.z = 1 >>> assert(isinstance(x.y, Yaco)) >>> s = x.simple() >>> assert(s['y']['z'] == 1) >>> assert(isinstance(s['y'], dict)) >>> assert(not isinstance(s['y'], Yaco))
-
soft_update
(data)¶ As update - but only update keys that do not have a value.
Note - lists are completely
>>> d1 = {'a' : [1,2,3,{'b': 12}], 'd' : {'e': 72}} >>> d2 = {'a' : [2,3,4,{'b': 12}], 'd' : {'e': 73, 'f': 18}, 'c' : 18} >>> v = Yaco(d1) >>> assert(v.a[2] == 3) >>> assert(v.d.e == 72) >>> v.soft_update(d2) >>> assert(v.d.e == 72) >>> assert(v.d.f == 18) >>> assert(v.a[2] == 3)
-
update
(data)¶ >>> v = Yaco({'a' : [1,2,3,{'b' : 12}]}) >>> assert(v.a[3].b == 12)
>>> v = Yaco({'a' : [1,2,3,[1,{'b' : 12}]]}) >>> assert(v.a[3][1].b == 12)
-
class
Yaco.
YacoDir
(dirname, pattern='*.config')¶ As Yaco, but load all files in a directory on top of each other.
Order of loading is the alphanumerical sort of filenames
files in subdirectories are loaded into leaves e.g. a file in /tmp/test/sub/a.yaml with only (x=1) will end up as follows:
y = YacoDir(‘/tmp/test’) y.sub.x == 1Note, YacoDir will try to cache itself in a .yacodir.cache file in the root of the dirname if the modification date of this file is the same as the directory - that will be loaded instead.
-
load
(dirname, pattern)¶ Load from the defined directory
-
save
()¶ Save is disabled.
-