123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- __all__ = ['seqToKV', 'kvToSeq', 'dictToKV', 'kvToDict']
- from openid import oidutil
- import types
- class KVFormError(ValueError):
- pass
- def seqToKV(seq, strict=False):
- """Represent a sequence of pairs of strings as newline-terminated
- key:value pairs. The pairs are generated in the order given.
- @param seq: The pairs
- @type seq: [(str, (unicode|str))]
- @return: A string representation of the sequence
- @rtype: str
- """
- def err(msg):
- formatted = 'seqToKV warning: %s: %r' % (msg, seq)
- if strict:
- raise KVFormError(formatted)
- else:
- oidutil.log(formatted)
- lines = []
- for k, v in seq:
- if isinstance(k, types.StringType):
- k = k.decode('UTF8')
- elif not isinstance(k, types.UnicodeType):
- err('Converting key to string: %r' % k)
- k = str(k)
- if '\n' in k:
- raise KVFormError(
- 'Invalid input for seqToKV: key contains newline: %r' % (k,))
- if ':' in k:
- raise KVFormError(
- 'Invalid input for seqToKV: key contains colon: %r' % (k,))
- if k.strip() != k:
- err('Key has whitespace at beginning or end: %r' % (k,))
- if isinstance(v, types.StringType):
- v = v.decode('UTF8')
- elif not isinstance(v, types.UnicodeType):
- err('Converting value to string: %r' % (v,))
- v = str(v)
- if '\n' in v:
- raise KVFormError(
- 'Invalid input for seqToKV: value contains newline: %r' % (v,))
- if v.strip() != v:
- err('Value has whitespace at beginning or end: %r' % (v,))
- lines.append(k + ':' + v + '\n')
- return ''.join(lines).encode('UTF8')
- def kvToSeq(data, strict=False):
- """
- After one parse, seqToKV and kvToSeq are inverses, with no warnings::
- seq = kvToSeq(s)
- seqToKV(kvToSeq(seq)) == seq
- """
- def err(msg):
- formatted = 'kvToSeq warning: %s: %r' % (msg, data)
- if strict:
- raise KVFormError(formatted)
- else:
- oidutil.log(formatted)
- lines = data.split('\n')
- if lines[-1]:
- err('Does not end in a newline')
- else:
- del lines[-1]
- pairs = []
- line_num = 0
- for line in lines:
- line_num += 1
- # Ignore blank lines
- if not line.strip():
- continue
- pair = line.split(':', 1)
- if len(pair) == 2:
- k, v = pair
- k_s = k.strip()
- if k_s != k:
- fmt = ('In line %d, ignoring leading or trailing '
- 'whitespace in key %r')
- err(fmt % (line_num, k))
- if not k_s:
- err('In line %d, got empty key' % (line_num,))
- v_s = v.strip()
- if v_s != v:
- fmt = ('In line %d, ignoring leading or trailing '
- 'whitespace in value %r')
- err(fmt % (line_num, v))
- pairs.append((k_s.decode('UTF8'), v_s.decode('UTF8')))
- else:
- err('Line %d does not contain a colon' % line_num)
- return pairs
- def dictToKV(d):
- seq = d.items()
- seq.sort()
- return seqToKV(seq)
- def kvToDict(s):
- return dict(kvToSeq(s))
|