Dave Cinege Git Repo thesaurus / 3dccbf9
README.rst updates Dave Cinege 2 years ago
5 changed file(s) with 86 addition(s) and 46 deletion(s). Raw diff Collapse all Expand all
0 This is Python Thesaurus and ThesaurusCfg
0 Python Thesaurus and ThesaurusCfg
11 =========================================
22 Copyright (c) 2012-2019 Dave Cinege. All rights reserved.
33
44 See the end of this file for further copyright and license information
55
6 .. contents::
76
87 Quick start
98 ------------
1716 General Information
1817 -------------------
1918
20 - Source code: https://git.cinege.com//thesaurus
21 - Telegram Group: https://t.me/PythonThesaurus
19 :Source code: https://git.cinege.com//thesaurus
20 :Telegram Group: https://t.me/PythonThesaurus
2221
2322
2423 At the momement there is no email list, wiki, etc.
9392
9493
9594
95 Copyright and License Information
96 ---------------------------------
9697
98 Copyright (c) 2012 - 2019 Dave Cinege. All rights reserved.
99
100 See the file "LICENSE" for information on the history of this software,
101 terms & conditions for usage, and a DISCLAIMER OF ALL WARRANTIES.
97102
98103
99104
171176 a dictionary that could act (sort of) like a class, Thesaurus may be for you.
172177
173178
174 Copyright and License Information
175 ---------------------------------
176179
177 Copyright (c) 2012 - 2019 Dave Cinege. All rights reserved.
178
179 See the file "LICENSE" for information on the history of this software,
180 terms & conditions for usage, and a DISCLAIMER OF ALL WARRANTIES.
00 ###
11 # Python Thesaurus - A different way to call a dictionary.
22 #
3 # Copyright (c) 2013-2019 Dave Cinege
3 # Copyright (c) 2012-2019 Dave Cinege
44 #
55 # Licensed under the Apache License, Version 2.0 (the "License");
66 # you may not use this file except in compliance with the License.
1616 ###
1717 from __future__ import print_function
1818
19 __VERSION__ = (2, 9, 9, 20190910)
19 __VERSION__ = (2, 9, 0, 20190910)
2020
2121 import os
2222 import sys
2525
2626 from string import Template
2727
28 from thesaurus import thes, thesext, key_treepath
28 from thesaurus import thes, thesext
2929
3030 class cfg_types (object):
3131 class __EXAMPLE (object):
6060 return ''
6161 s = ''
6262 for i in val:
63 s += '"%s" ' % (i.replace('"','\\"').replace("'","\\'"))
63 s += '"%s" ' % (i.replace('"','\\"'))
6464 return s[:-1]
6565 class str_to_bool (object):
6666 """"Support 3 values: True, False, None"""
6767 def set (self, key, val, curval):
6868 if val in (True, False, None):
6969 return val
70 raise TypeError(s)
70 raise ValueError(s)
7171 def parse (self, key, val):
7272 s = val.lower()
7373 if s in ('true', 'yes', 'on', '1'):
7676 return False
7777 if s in ('none', ''):
7878 return None
79 raise TypeError(s)
79 raise ValueError(s)
8080 def dump (self, key, val):
8181 if val == None:
8282 return 'None'
8383 return bool(val)
84
84 class ipv4 (object):
85 def set (self, key, val, curval):
86 return self.parse(key, val)
87 def parse (self, key, val):
88 l = val.split('.')
89 if len(l) != 4:
90 raise ValueError(val)
91 for i in l:
92 try:
93 i = int(i)
94 except:
95 raise ValueError(val)
96 if i < 0 or i > 255:
97 raise ValueError(val)
98 return val
99
85100 class configparser (object):
86101 def __init__(self, *args, **kwargs):
87102 self._thes_type = thesext
90105 self._value_rstrip = True
91106 for k,v in kwargs.items():
92107 setattr(self, '_'+k, v)
108 def split_key (self, key):
109 lex = shlex.shlex(key, posix=True)
110 lex.whitespace_split = True
111 lex.whitespace = '.'
112 return list(lex)
93113 def read(self, filename=None, t=None):
94114 if t == None: t = self._thes_type()
95115 t = self._thes_type()
98118 def readfp (self, fp=None, t=None):
99119 if t == None: t = self._thes_type()
100120 return self.parse(t, fp.read())
101 def parse (self, t=None, s='', func_map={}, set_map={}, parse_map={}, dump_map={}):
102 """Original trimmed text is returned, sutain for input back to parse"""
121 def parse (self, t=None, s='', func_map={}):
122 """Original trimmed text is returned, sustain for input back to parse"""
103123 def full_key (root_key, key):
104124 if root_key != '':
105125 return root_key+'.'+key
143163 # FIX ME suport empty root sections without []
144164 if line.startswith('[') and line.rstrip().endswith(']'):
145165 root_key = line.rstrip()[1:-1].strip() # '[]' section resets root_key
146 if root_key != '' and root_key not in t:
147 t.set_path(root_key, self._thes_type()) # FIX me use parent class
166 root_keypath = self.split_key(root_key)
167 if root_key != '' and root_keypath not in t:
168 t.set_path(root_keypath, self._thes_type()) # FIX me use parent class
148169 continue
149170
150171 key,value = re_sep.split(line, 1)
166187 key = full_key(root_key, key.strip())
167188 funcname = funcvar[:-1].strip()
168189
190
191 keypath = self.split_key(key)
192 if len(keypath) > 1 and keypath[:-1] not in t:
193 t.set_path(keypath, self._thes_type())
194 o = t[keypath[:-1]]
195 key = keypath[-1]
196
169197 if funcname and funcname in func_map:
170198 if hasattr(func_map[funcname], 'parse'):
171 parse_map[key] = func_map[funcname]().parse
172 if key in parse_map:
173 value = parse_map[key](key, value)
174 t.set_path(key, value) # Apply parse_map prior to set. NOTE: addition applicaiton WILL applied set_map
199 o._ThesConf__parse_map[key] = func_map[funcname]().parse
200 if key in o._ThesConf__parse_map:
201 value = o._ThesConf__parse_map[key](key, value)
202 o[key] = value
175203
176204 if funcname and funcname in func_map:
177205 if hasattr(func_map[funcname], 'set'):
178 set_map[key] = func_map[funcname]().set
206 o._ThesConf__set_map[key] = func_map[funcname]().set
179207 if hasattr(func_map[funcname], 'dump'):
180 dump_map[key] = func_map[funcname]().dump
208 o._ThesConf__dump_map[key] = func_map[funcname]().dump
181209
182210 return t
183211 def write (self, fp=None, t=None):
184212 if t == None: t = self._thes_type()
185213 return self.dump(t, fp.read())
186214
187 def dump(self, t, sections=0, empty_sect=True, dump_map={}):
188 def recursedict(d, sections, empty_sect, dump_map, key_tree=[], depth=0, s='', r=''):
215 def dump(self, t, sections=0, empty_sect=True):
216 def recursedict(d, sections, empty_sect, key_tree=[], depth=0, s='', r=''):
189217 for k,v in iter(d.items()):
190218 if hasattr(v, 'keys'):
191 key_tree.append(k)
192 r = recursedict(v, sections, empty_sect, dump_map, key_tree, depth+1)
219 if '.' in k:
220 key_tree.append("'"+k+"'")
221 else:
222 key_tree.append(k)
223 r = recursedict(v, sections, empty_sect, key_tree, depth+1)
193224 if sections and depth < sections:
194225 if r or empty_sect:
195226 if s != '': s += '\n' # Not at top of output
201232 else:
202233 if sections and depth == 0 and r: # More root level values after recursing
203234 s += '\n[]\n'; r = '' # Reset section so not absorbed by previous
204 if k in dump_map:
205 v = dump_map[k](k, v)
235
236 if k in d._ThesConf__dump_map:
237 v = d._ThesConf__dump_map[k](k, v)
238
206239 if '\n' in str(v):
207240 v = ':\n\t%s\n' % (v.replace('\n','\n\t'))
208241 else:
212245 else:
213246 s += key_treepath(key_tree[sections:], k) + v
214247 return s
215 return recursedict(t, sections, empty_sect, dump_map)
248 return recursedict(t, sections, empty_sect)
216249
217250 class ThesConf (object):
218251 def __init__(self, *args, **kwargs):
225258 return self.parse(f.read(), *args, **kwargs)
226259 def parse (self, data, *args, **kwargs):
227260 func_map=mapper(cfg_types())
228 return configparser(thes_type=self.__class__).parse(self, data, func_map=func_map,
229 set_map=self.__set_map, parse_map=self.__parse_map, dump_map=self.__dump_map)
261 return configparser(thes_type=self.__class__).parse(self, data, func_map=func_map)
230262 def write (self, fp, *args, **kwargs):
231263 fp.write(self.dump(*args, **kwargs))
232264 def dump (self, sections=0, empty_sect=True):
233 return configparser(thes_type=self.__class__).dump(self, sections, empty_sect, dump_map=self.__dump_map)
265 return configparser(thes_type=self.__class__).dump(self, sections, empty_sect)
234266
235267
236268 class ThesaurusCfg (thesext, ThesConf):
363395 try:
364396 f.close()
365397 except: pass
366
398
399 def key_treepath (key_tree, *keys):
400 """''.join keeps playing with my emotions"""
401 return '.'.join(key_tree+list(keys))
367402
368403 #Define prefered import name
369404 thescfg = ThesaurusCfg
00 """
11 thesauruscfg_sample.cfg
2 Copyright (c) 2013-2019 Dave Cinege
3 Licensed under the Apache License, Version 2.0 (the "License");
2 Copyright (c) 2019 Dave Cinege
3 Licensed under the Apache License, Version 2.0
44
55 VERSION = 20191112
66
8080 # Keypath and value
8181 program.name = thesauruscfg_sample.py
8282
83 # Multi-line keypath and value
83 # keypath and multi-line value
8484 program.description:
8585 This program is to test the functionality of the ThesaurusCfg
8686 Python module. We prefer ':\n' value delimiters for multi-line.
9595
9696 # Reset (clear) the keypath prefix 'section'. While you can do this,
9797 # it's of course cleaner to keep the root level keys all together.
98 # Remember that Thesaurus is ORDERED so this will define after the above
99 # keypaths, and not right after the orginal root level keys.
98100 []
99101 abc_2 (static_int) = 1234
100102
103 # We will apply these defaults to the below gateways using Thesaurus.mesh(),
104 # so that every gateway always has the default values, without having to
105 # list them multiple times.
101106 [defaults.gateways]
102107 table = 10
103108 ifname = eth0
1616 ###
1717 from __future__ import print_function
1818
19 __VERSION__ = (2, 9, 0, 20191112)
19 __VERSION__ = (2, 9, 0, 20191113)
2020
2121 import os
2222 import sys
3131 cfg.print_tree()
3232 print('---')
3333
34 # mesh in the default gateways values (don't overwrite existing)
34 # mesh in the default.gateways values (don't overwrite existing)
3535 # FIX ME not yet copying the coercion methods
3636 for t in cfg.networks.values():
3737 t.gateways.mesh(cfg.defaults.gateways)
4343 # abc is using the static_int() coercion method. The method not only
4444 # converts to and from an int, it will not allow further value assignment
4545 # keeping it static.
46 oldabc = cfg.abc
4647 cfg.abc = 0
47 cfg['abc'] = 0
48 if cfg.abc == 123:
49 print('abc: static value = 123 will not change.')
48 cfg['abc'] = 'even the wrong type'
49 if oldabc == cfg.abc:
50 print('abc: static value will not change.')
5051 else:
5152 print('abc: is broken!')
5253