-
Notifications
You must be signed in to change notification settings - Fork 14
/
config.py
147 lines (96 loc) · 3.66 KB
/
config.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import yaml
import sys
import copy
from os import path, listdir
from collections import OrderedDict, Sequence, Mapping
class Config(yaml.Loader):
eidetic = dict()
def __init__(self, stream):
self._root = path.split(stream.name)[0]
super(Config, self).__init__(stream)
def include(self, node):
"""Include a YAML file within another YAML file"""
filepath = path.join(self._root, self.construct_scalar(node))
if path.isdir(filepath):
for filename in listdir(filepath):
if path.isfile(filename):
return self.load(filename)
else:
return self.load(filepath)
def sequence(self, node):
return YamlList(self.construct_object(child) for child in node.value)
def mapping(self, node):
make_obj = self.construct_object
return YamlDict((make_obj(k), make_obj(v)) for k, v in node.value)
def load(self, path):
if path not in self.eidetic:
with open(path, 'r') as filestream:
self.eidetic.update({ path: yaml.load(filestream, Config) })
return self.eidetic.get(path, dict())
class YamlDict(OrderedDict):
def __init__(self, *args, **kwargs):
super(YamlDict, self).__init__(*args, **kwargs)
self.__root = self
def __getattr__(self, key):
if key in self:
return self[key]
return super(YamlDict, self).__getattribute__(key)
def __getitem__(self, key):
v = super(YamlDict, self).__getitem__(key)
if isinstance(v, basestring):
v = v.format(**self.__root)
return v
def __setitem__(self, key, value):
if isinstance(value, Mapping) and not isinstance(value, YamlDict):
value = YamlDict(value)
elif isinstance(value, basestring):
pass
elif isinstance(value, Sequence) and not isinstance(value, YamlList):
value = YamlList(value)
super(YamlDict, self).__setitem__(key, value)
def copy(self):
return copy.deepcopy(self)
def setAsRoot(self, root=None):
if root is None:
root = self
self.__root = root
for k, v in self.iteritems():
if hasattr(v, 'setAsRoot'):
v.setAsRoot(root)
class YamlList(list):
ROOT_NAME = 'root'
def __init__(self, *args, **kwargs):
super(YamlList, self).__init__(*args, **kwargs)
self.__root = {YamlList.ROOT_NAME: self}
def __getitem__(self, key):
v = super(YamlList, self).__getitem__(key)
if isinstance(v, basestring):
v = v.format(**self.__root)
return v
def __setitem__(self, key, value):
if isinstance(value, Mapping) and not isinstance(value, YamlDict):
value = YamlDict(value)
elif isinstance(value, Sequence) and not isinstance(value, YamlList):
value = YamlList(value)
super(YamlList, self).__setitem__(key, value)
def copy(self, *args):
return copy.deepcopy(self)
def setAsRoot(self, root=None):
if root is None:
root = {YamlList.ROOT_NAME: self}
self.__root = root
for v in self:
if hasattr(v, 'setAsRoot'):
v.setAsRoot(root)
def load_config(config_file):
try:
stream = file(config_file, 'r')
data = yaml.load(stream, Config)
if data is not None:
data.setAsRoot()
return data
except Exception as e:
pass
Config.add_constructor('!include', Config.include)
Config.add_constructor(u'tag:yaml.org,2002:seq', Config.sequence)
Config.add_constructor(u'tag:yaml.org,2002:map', Config.mapping)