0
|
1 import re
|
|
2 import yaml
|
|
3
|
|
4
|
|
5 class Configuration(object):
|
|
6 def __init__(self, values=None, validate=True):
|
|
7 self._values = {}
|
|
8 if values is not None:
|
|
9 self.set_all(values, validate)
|
|
10
|
|
11 def set_all(self, values, validate=True):
|
|
12 if validate:
|
|
13 self._validateAll(values)
|
|
14 self._values = values
|
|
15
|
|
16 def get(self, key_path=None):
|
|
17 self._ensureLoaded()
|
|
18 if key_path is None:
|
|
19 return self._values
|
|
20 bits = key_path.split('/')
|
|
21 cur = self._values
|
|
22 for b in bits:
|
|
23 cur = cur.get(b)
|
|
24 if cur is None:
|
|
25 return None
|
|
26 return cur
|
|
27
|
|
28 def set(self, key_path, value):
|
|
29 self._ensureLoaded()
|
|
30 value = self._validateValue(key_path, value)
|
|
31 bits = key_path.split('/')
|
|
32 bitslen = len(bits)
|
|
33 cur = self._values
|
|
34 for i, b in enumerate(bits):
|
|
35 if i == bitslen - 1:
|
|
36 cur[b] = value
|
|
37 else:
|
|
38 if b not in cur:
|
|
39 cur[b] = {}
|
|
40 cur = cur[b]
|
|
41
|
|
42 def has(self, key_path):
|
|
43 self._ensureLoaded()
|
|
44 bits = key_path.split('/')
|
|
45 cur = self._values
|
|
46 for b in bits:
|
|
47 cur = cur.get(b)
|
|
48 if cur is None:
|
|
49 return False
|
|
50 return True
|
|
51
|
|
52 def merge(self, other):
|
|
53 self._ensureLoaded()
|
|
54 merge_dicts(self._values, other._values,
|
|
55 validator=self._validateValue)
|
|
56
|
|
57 def _ensureLoaded(self):
|
|
58 if self._values is None:
|
|
59 self._load()
|
|
60
|
|
61 def _load(self):
|
|
62 self._values = self._validateAll({})
|
|
63
|
|
64 def _validateAll(self, values):
|
|
65 return values
|
|
66
|
|
67 def _validateValue(self, key_path, value):
|
|
68 return value
|
|
69
|
|
70
|
|
71 def merge_dicts(local_cur, incoming_cur, parent_path=None, validator=None):
|
|
72 if validator is None:
|
|
73 validator = lambda k, v: v
|
|
74
|
|
75 for k, v in incoming_cur.iteritems():
|
|
76 key_path = k
|
|
77 if parent_path is not None:
|
|
78 key_path = parent_path + '/' + k
|
|
79
|
|
80 local_v = local_cur.get(k)
|
|
81 if local_v is not None:
|
|
82 if isinstance(v, dict) and isinstance(local_v, dict):
|
|
83 local_cur[k] = merge_dicts(local_v, v)
|
|
84 elif isinstance(v, list) and isinstance(local_v, list):
|
|
85 local_cur[k] = v + local_v
|
|
86 else:
|
|
87 local_cur[k] = validator(key_path, v)
|
|
88 else:
|
|
89 local_cur[k] = validator(key_path, v)
|
|
90
|
|
91
|
|
92 header_regex = re.compile(
|
|
93 r'(---\s*\n)(?P<header>(.*\n)*?)^(---\s*\n)', re.MULTILINE)
|
|
94
|
|
95
|
|
96 def parse_config_header(text):
|
|
97 m = header_regex.match(text)
|
|
98 if m is not None:
|
|
99 header = unicode(m.group('header'))
|
|
100 config = yaml.safe_load(header)
|
|
101 offset = m.end()
|
|
102 else:
|
|
103 config = {}
|
|
104 offset = 0
|
|
105 return config, offset
|
|
106
|