2 Copyright (C) 2016, Digium, Inc. 4 This program is free software, distributed under the terms of 5 the GNU General Public License Version 2. 12 from astdicts
import OrderedDict
13 from astdicts
import MultiOrderedDict
17 """Merges values from right into left.""" 18 if isinstance(left, list):
21 vals0 = left[key]
if key
in left
else []
22 vals1 = right[key]
if key
in right
else []
24 return vals0 + [i
for i
in vals1
if i
not in vals0]
31 A Section is a MultiOrderedDict itself that maintains a list of 32 key/value options. However, in the case of an Asterisk config 33 file a section may have other defaults sections that is can pull 34 data from (i.e. templates). So when an option is looked up by key 35 it first checks the base section and if not found looks in the 36 added default sections. If not found at that point then a 'KeyError' 41 def __init__(self, defaults=None, templates=None):
42 MultiOrderedDict.__init__(self)
45 self.
id = Section.count
46 self.
_defaults = []
if defaults
is None else defaults
47 self.
_templates = []
if templates
is None else templates
51 Use self.id as means of determining equality 53 return (self.
id > other.id) - (self.
id < other.id)
57 Use self.id as means of determining equality 59 return self.
id == other.id
63 Use self.id as means of determining equality 65 return self.
id < other.id
69 Use self.id as means of determining equality 71 return self.
id > other.id
75 Use self.id as means of determining equality 77 return self.
id <= other.id
81 Use self.id as means of determining equality 83 return self.
id >= other.id
85 def get(self, key, from_self=True, from_templates=True,
88 Get the values corresponding to a given key. The parameters to this 89 function form a hierarchy that determines priority of the search. 90 from_self takes priority over from_templates, and from_templates takes 91 priority over from_defaults. 94 from_self - If True, search within the given section. 95 from_templates - If True, search in this section's templates. 96 from_defaults - If True, search within this section's defaults. 98 if from_self
and key
in self:
99 return MultiOrderedDict.__getitem__(self, key)
108 return t.get(key,
True, from_templates, from_defaults)
115 return d.get(key,
True, from_templates, from_defaults)
123 Get the value for the given key. If it is not found in the 'self' 124 then check inside templates and defaults before declaring raising 125 a KeyError exception. 129 def keys(self, self_only=False):
131 Get the keys from this section. If self_only is True, then 132 keys from this section's defaults and templates are not 133 included in the returned value 135 res = MultiOrderedDict.keys(self)
152 Add a list of defaults to the section. Defaults are 153 sections such as 'general' 161 Add a list of templates to the section. 168 """Return a list of values for a given key merged from default(s)""" 189 COMMENT_START =
';--' 192 DEFAULTSECT =
'general' 196 """Remove any commented elements from the line.""" 198 return line, is_comment
201 part = line.partition(COMMENT_END)
207 part = line.partition(COMMENT_START)
208 if part[1]
and not part[2].startswith(
'-'):
211 has_comment = part[0].partition(COMMENT)
214 return has_comment[0],
False 220 return part[0].strip(),
True 223 return ''.join([part[0].strip(),
' ', line]).rstrip(),
False 226 match = re.match(
r'.*?([^\\];)', line)
230 line = line[0:(match.end()-1)]
231 if line.startswith(
";"):
235 return line.replace(
"\\",
"").strip(),
False 239 Checks to see if the given line is an include. If so return the 240 included filename, otherwise None. 243 match = re.match(
'^#include\s*([^;]+).*$', line)
245 trimmed = match.group(1).rstrip()
246 quoted = re.match(
'^"([^"]+)"$', trimmed)
248 return quoted.group(1)
249 bracketed = re.match(
'^<([^>]+)>$', trimmed)
251 return bracketed.group(1)
258 Checks to see if the given line is a section. If so return the section 259 name, otherwise return 'None'. 262 if not line.startswith(
'['):
263 return None,
False, []
265 section, delim, templates = line.partition(
']')
267 return section[1:],
False, []
270 templates = templates.replace(
'(',
"").
replace(
')',
"").split(
',')
272 templates = [i.strip()
for i
in templates]
274 templates.remove(
'!')
275 return section[1:],
True, templates
277 return section[1:],
False, templates
281 """Parses the line as an option, returning the key/value pair.""" 282 data = re.split(
'=>?', line, 1)
284 return data[0].rstrip(), data[1].lstrip()
291 Given a list of mult-dicts, return the multi-dict that contains 292 the given key/value pair. 296 return key
in d
and val
in d[key]
299 return [d
for d
in mdicts
if found(d)][0]
301 raise LookupError(
"Dictionary not located for key = %s, value = %s" 306 """Write the contents of the mdicts to the specified config file""" 307 for section, sect_list
in mdicts.iteritems():
309 for sect
in sect_list:
310 config_file.write(
"[%s]\n" % section)
311 for key, val_list
in sect.iteritems():
316 key_val +=
" = " +
str(v)
317 config_file.write(
"%s\n" % (key_val))
318 config_file.write(
"\n")
331 """Given a list of sections, try to find value(s) for the given key.""" 333 sections.sort(reverse=
True)
337 return s.get(key, from_defaults=
False)
346 return s.get(key, from_self=
False, from_templates=
False)
356 """Retrieves a list of dictionaries for a default section.""" 361 Adds a default section to defaults, returning the 362 default Section object. 364 if template_keys
is None:
372 """Retrieves a list of dictionaries for a section.""" 377 Retrieve a list of sections that have values for the given key. 378 The attr parameter can be used to control what part of the parser 379 to retrieve values from. 386 sections = getattr(self, attr)
387 res = sections[key]
if key
in sections
else []
388 searched.append(self)
390 res.extend(list(itertools.chain(*[
391 incl.get_sections(key, attr, searched)
392 for incl
in self.
_includes.itervalues()])))
399 Retrieve a list of defaults that have values for the given key. 405 Create a new section in the configuration. The name of the 406 new section is the 'key' parameter. 408 if template_keys
is None:
413 for t
in template_keys:
416 mdicts.insert(0, key, res)
424 Add a new #include file to the configuration. 433 def get(self, section, key):
434 """Retrieves the list of values from a section for a key.""" 446 raise LookupError(
"key %r not found for section %r" 451 Retrieves the list of values from a section for a list of keys. 452 This method is intended to be used for equivalent keys. Thus, as soon 453 as any match is found for any key in the key_list, the match is 454 returned. This does not concatenate the lookups of all of the keys 459 return self.
get(section, i)
464 raise LookupError(
"keys %r not found for section %r" %
467 def set(self, section, key, val):
468 """Sets an option in the given section.""" 472 self.
section(section)[0][key] = val
474 self.
defaults(section)[0][key] = val
476 def read(self, filename, sect=None):
477 """Parse configuration information from a file""" 479 with open(filename,
'rt')
as config_file:
480 self.
_read(config_file, sect)
482 print(
"Could not open file " + filename +
" for reading")
484 def _read(self, config_file, sect):
485 """Parse configuration information from the config_file""" 487 for line
in config_file:
495 for incl
in sorted(glob.iglob(include_name)):
497 parser.read(incl, sect)
500 section, is_template, templates =
try_section(line)
502 if section == DEFAULTSECT
or is_template:
510 raise Exception(
"Section not defined before assignment")
514 """Write configuration information out to a file""" 516 for key, val
in self.
_includes.iteritems():
518 config_file.write(
'#include "%s"\n' % key)
520 config_file.write(
'\n')
525 with open(config_file,
'wt')
as fp:
528 print(
"Could not open file " + config_file +
" for writing")
def set(self, section, key, val)
def _read(self, config_file, sect)
def remove_comment(line, is_comment)
def insert(self, i, key, val)
def get_sections(self, key, attr='_sections', searched=None)
def keys(self, self_only=False)
def find_dict(mdicts, key, val)
def add_section(self, key, template_keys=None, mdicts=None)
def add_templates(self, templates)
def multi_get(self, section, key_list)
def write(self, config_file)
def __init__(self, parent=None)
def read(self, filename, sect=None)
def merge_values(left, right, key)
def add_include(self, filename, parser=None)
def __getitem__(self, key)
def __init__(self, defaults=None, templates=None)
def get_defaults(self, key)
static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
def get(self, key, from_self=True, from_templates=True, from_defaults=True)
def add_default(self, key, template_keys=None)
def write_dicts(config_file, mdicts)
def find_value(self, sections, key)
def add_defaults(self, defaults)
def get_merged(self, key)
def get(self, section, key)