Advanced fetchart source config: write (restore?) confit' as_pairs()
@@ -413,6 +413,12 @@ class ConfigView(object):
"""
return self.get(StrSeq(split=split))
+ def as_pairs(self, default_value=None):
+ """Get the value as a sequence of pairs of two strings. Equivalent to
+ `get(Pairs())`.
+ """
+ return self.get(Pairs(default_value=default_value))
+
def as_str(self):
"""Get the value as a (Unicode) string. Equivalent to
`get(unicode)` on Python 2 and `get(str)` on Python 3.
@@ -1242,30 +1248,75 @@ class StrSeq(Template):
super(StrSeq, self).__init__()
self.split = split
+ def _convert_value(self, x, view):
+ if isinstance(x, STRING):
+ return x
+ elif isinstance(x, bytes):
+ return x.decode('utf-8', 'ignore')
+ else:
+ self.fail(u'must be a list of strings', view, True)
+
def convert(self, value, view):
if isinstance(value, bytes):
value = value.decode('utf-8', 'ignore')
if isinstance(value, STRING):
if self.split:
- return value.split()
+ value = value.split()
+ else:
+ value = [value]
else:
- return [value]
-
try:
value = list(value)
except TypeError:
self.fail(u'must be a whitespace-separated string or a list',
view, True)
- def convert(x):
- if isinstance(x, STRING):
- return x
- elif isinstance(x, bytes):
- return x.decode('utf-8', 'ignore')
+ return [self._convert_value(v, view) for v in value]
+
+
+class Pairs(StrSeq):
+ """A template for ordered key-value pairs.
+
+ This can either be given with the same syntax as for `StrSeq` (i.e. without
+ values), or as a list of strings and/or single-element mappings such as::
+
+ - key: value
+ - [key, value]
+ - key
+
+ The result is a list of two-element tuples. If no value is provided, the
+ `default_value` will be returned as the second element.
+ """
+
+ def __init__(self, default_value=None):
+ """Create a new template.
+
+ `default` is the dictionary value returned for items that are not
+ a mapping, but a single string.
+ """
+ super(Pairs, self).__init__(split=True)
+ self.default_value = default_value
+
+ def _convert_value(self, x, view):
+ try:
+ return (super(Pairs, self)._convert_value(x, view),
+ self.default_value)
+ except ConfigTypeError:
+ if isinstance(x, collections.Mapping):
+ if len(x) != 1:
+ self.fail(u'must be a single-element mapping', view, True)
+ k, v = iter_first(x.items())
+ elif isinstance(x, collections.Sequence):
+ if len(x) != 2:
+ self.fail(u'must be a two-element list', view, True)
+ k, v = x
else:
- self.fail(u'must be a list of strings', view, True)
- return list(map(convert, value))
+ # Is this even possible? -> Likely, if some !directive cause
+ # YAML to parse this to some custom type.
+ self.fail(u'must be a single string, mapping, or a list' + str(x), view, True)
+ return (super(Pairs, self)._convert_value(k, view),
+ super(Pairs, self)._convert_value(v, view))
class Filename(Template):
