blob: 5d0ebced0e149a907df3e4595dd0a3f7ad2312c7 [file] [log] [blame]
Joe Gregorio48d361f2010-08-18 13:19:21 -04001# Early, and incomplete implementation of -04.
2#
3import re
4import urllib
5
6RESERVED = ":/?#[]@!$&'()*+,;="
7OPERATOR = "+./;?|!@"
8EXPLODE = "*+"
9MODIFIER = ":^"
10TEMPLATE = re.compile(r"{(?P<operator>[\+\./;\?|!@])?(?P<varlist>[^}]+)}", re.UNICODE)
11VAR = re.compile(r"^(?P<varname>[^=\+\*:\^]+)((?P<explode>[\+\*])|(?P<partial>[:\^]-?[0-9]+))?(=(?P<default>.*))?$", re.UNICODE)
12
13def _tostring(varname, value, explode, operator, safe=""):
14 if type(value) == type([]):
15 if explode == "+":
16 return ",".join([varname + "." + urllib.quote(x, safe) for x in value])
17 else:
18 return ",".join([urllib.quote(x, safe) for x in value])
19 if type(value) == type({}):
20 keys = value.keys()
21 keys.sort()
22 if explode == "+":
23 return ",".join([varname + "." + urllib.quote(key, safe) + "," + urllib.quote(value[key], safe) for key in keys])
24 else:
25 return ",".join([urllib.quote(key, safe) + "," + urllib.quote(value[key], safe) for key in keys])
26 else:
27 return urllib.quote(value, safe)
28
29
30def _tostring_path(varname, value, explode, operator, safe=""):
31 joiner = operator
32 if type(value) == type([]):
33 if explode == "+":
34 return joiner.join([varname + "." + urllib.quote(x, safe) for x in value])
35 elif explode == "*":
36 return joiner.join([urllib.quote(x, safe) for x in value])
37 else:
38 return ",".join([urllib.quote(x, safe) for x in value])
39 elif type(value) == type({}):
40 keys = value.keys()
41 keys.sort()
42 if explode == "+":
43 return joiner.join([varname + "." + urllib.quote(key, safe) + joiner + urllib.quote(value[key], safe) for key in keys])
44 elif explode == "*":
45 return joiner.join([urllib.quote(key, safe) + joiner + urllib.quote(value[key], safe) for key in keys])
46 else:
47 return ",".join([urllib.quote(key, safe) + "," + urllib.quote(value[key], safe) for key in keys])
48 else:
49 if value:
50 return urllib.quote(value, safe)
51 else:
52 return ""
53
54def _tostring_query(varname, value, explode, operator, safe=""):
55 joiner = operator
56 varprefix = ""
57 if operator == "?":
58 joiner = "&"
Joe Gregorio266c6442011-02-23 16:08:54 -050059 varprefix = varname + "="
Joe Gregorio48d361f2010-08-18 13:19:21 -040060 if type(value) == type([]):
61 if 0 == len(value):
62 return ""
63 if explode == "+":
64 return joiner.join([varname + "=" + urllib.quote(x, safe) for x in value])
65 elif explode == "*":
66 return joiner.join([urllib.quote(x, safe) for x in value])
67 else:
68 return varprefix + ",".join([urllib.quote(x, safe) for x in value])
69 elif type(value) == type({}):
70 if 0 == len(value):
71 return ""
72 keys = value.keys()
73 keys.sort()
74 if explode == "+":
75 return joiner.join([varname + "." + urllib.quote(key, safe) + "=" + urllib.quote(value[key], safe) for key in keys])
76 elif explode == "*":
77 return joiner.join([urllib.quote(key, safe) + "=" + urllib.quote(value[key], safe) for key in keys])
78 else:
79 return varprefix + ",".join([urllib.quote(key, safe) + "," + urllib.quote(value[key], safe) for key in keys])
80 else:
81 if value:
82 return varname + "=" + urllib.quote(value, safe)
83 else:
84 return varname
85
86TOSTRING = {
87 "" : _tostring,
88 "+": _tostring,
89 ";": _tostring_query,
90 "?": _tostring_query,
91 "/": _tostring_path,
92 ".": _tostring_path,
93 }
94
95
96def expand(template, vars):
97 def _sub(match):
98 groupdict = match.groupdict()
99 operator = groupdict.get('operator')
100 if operator is None:
101 operator = ''
102 varlist = groupdict.get('varlist')
103
Joe Gregorio266c6442011-02-23 16:08:54 -0500104 safe = "@"
Joe Gregorio48d361f2010-08-18 13:19:21 -0400105 if operator == '+':
106 safe = RESERVED
107 varspecs = varlist.split(",")
108 varnames = []
109 defaults = {}
110 for varspec in varspecs:
111 m = VAR.search(varspec)
112 groupdict = m.groupdict()
113 varname = groupdict.get('varname')
114 explode = groupdict.get('explode')
115 partial = groupdict.get('partial')
116 default = groupdict.get('default')
117 if default:
118 defaults[varname] = default
119 varnames.append((varname, explode, partial))
120
121 retval = []
122 joiner = operator
123 prefix = operator
124 if operator == "+":
125 prefix = ""
126 joiner = ","
127 if operator == "?":
128 joiner = "&"
129 if operator == "":
130 joiner = ","
131 for varname, explode, partial in varnames:
132 if varname in vars:
133 value = vars[varname]
134 #if not value and (type(value) == type({}) or type(value) == type([])) and varname in defaults:
135 if not value and value != "" and varname in defaults:
136 value = defaults[varname]
137 elif varname in defaults:
138 value = defaults[varname]
139 else:
140 continue
141 retval.append(TOSTRING[operator](varname, value, explode, operator, safe=safe))
142 if "".join(retval):
143 return prefix + joiner.join(retval)
144 else:
145 return ""
146
147 return TEMPLATE.sub(_sub, template)