webfaction and repo.or.cz deployment done
[worddb.git] / libs / openid / kvform.py
blobd875f56cd4762c500e34e7032668c3f532073ee5
1 __all__ = ['seqToKV', 'kvToSeq', 'dictToKV', 'kvToDict']
3 from openid import oidutil
5 import types
7 class KVFormError(ValueError):
8 pass
10 def seqToKV(seq, strict=False):
11 """Represent a sequence of pairs of strings as newline-terminated
12 key:value pairs. The pairs are generated in the order given.
14 @param seq: The pairs
15 @type seq: [(str, (unicode|str))]
17 @return: A string representation of the sequence
18 @rtype: str
19 """
20 def err(msg):
21 formatted = 'seqToKV warning: %s: %r' % (msg, seq)
22 if strict:
23 raise KVFormError(formatted)
24 else:
25 oidutil.log(formatted)
27 lines = []
28 for k, v in seq:
29 if isinstance(k, types.StringType):
30 k = k.decode('UTF8')
31 elif not isinstance(k, types.UnicodeType):
32 err('Converting key to string: %r' % k)
33 k = str(k)
35 if '\n' in k:
36 raise KVFormError(
37 'Invalid input for seqToKV: key contains newline: %r' % (k,))
39 if ':' in k:
40 raise KVFormError(
41 'Invalid input for seqToKV: key contains colon: %r' % (k,))
43 if k.strip() != k:
44 err('Key has whitespace at beginning or end: %r' % (k,))
46 if isinstance(v, types.StringType):
47 v = v.decode('UTF8')
48 elif not isinstance(v, types.UnicodeType):
49 err('Converting value to string: %r' % (v,))
50 v = str(v)
52 if '\n' in v:
53 raise KVFormError(
54 'Invalid input for seqToKV: value contains newline: %r' % (v,))
56 if v.strip() != v:
57 err('Value has whitespace at beginning or end: %r' % (v,))
59 lines.append(k + ':' + v + '\n')
61 return ''.join(lines).encode('UTF8')
63 def kvToSeq(data, strict=False):
64 """
66 After one parse, seqToKV and kvToSeq are inverses, with no warnings::
68 seq = kvToSeq(s)
69 seqToKV(kvToSeq(seq)) == seq
70 """
71 def err(msg):
72 formatted = 'kvToSeq warning: %s: %r' % (msg, data)
73 if strict:
74 raise KVFormError(formatted)
75 else:
76 oidutil.log(formatted)
78 lines = data.split('\n')
79 if lines[-1]:
80 err('Does not end in a newline')
81 else:
82 del lines[-1]
84 pairs = []
85 line_num = 0
86 for line in lines:
87 line_num += 1
89 # Ignore blank lines
90 if not line.strip():
91 continue
93 pair = line.split(':', 1)
94 if len(pair) == 2:
95 k, v = pair
96 k_s = k.strip()
97 if k_s != k:
98 fmt = ('In line %d, ignoring leading or trailing '
99 'whitespace in key %r')
100 err(fmt % (line_num, k))
102 if not k_s:
103 err('In line %d, got empty key' % (line_num,))
105 v_s = v.strip()
106 if v_s != v:
107 fmt = ('In line %d, ignoring leading or trailing '
108 'whitespace in value %r')
109 err(fmt % (line_num, v))
111 pairs.append((k_s.decode('UTF8'), v_s.decode('UTF8')))
112 else:
113 err('Line %d does not contain a colon' % line_num)
115 return pairs
117 def dictToKV(d):
118 seq = d.items()
119 seq.sort()
120 return seqToKV(seq)
122 def kvToDict(s):
123 return dict(kvToSeq(s))