148 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			148 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # Early, and incomplete implementation of -04.
 | |
| #
 | |
| import re
 | |
| import urllib
 | |
| 
 | |
| RESERVED = ":/?#[]@!$&'()*+,;="
 | |
| OPERATOR = "+./;?|!@"
 | |
| EXPLODE = "*+"
 | |
| MODIFIER = ":^"
 | |
| TEMPLATE = re.compile(r"{(?P<operator>[\+\./;\?|!@])?(?P<varlist>[^}]+)}", re.UNICODE)
 | |
| VAR = re.compile(r"^(?P<varname>[^=\+\*:\^]+)((?P<explode>[\+\*])|(?P<partial>[:\^]-?[0-9]+))?(=(?P<default>.*))?$", re.UNICODE)
 | |
| 
 | |
| def _tostring(varname, value, explode, operator, safe=""):
 | |
|   if type(value) == type([]):
 | |
|     if explode == "+":
 | |
|       return ",".join([varname + "." + urllib.quote(x, safe) for x in value])
 | |
|     else:
 | |
|       return ",".join([urllib.quote(x, safe) for x in value])
 | |
|   if type(value) == type({}):
 | |
|     keys = value.keys()
 | |
|     keys.sort()
 | |
|     if explode == "+":
 | |
|       return ",".join([varname + "." + urllib.quote(key, safe) + "," + urllib.quote(value[key], safe) for key in keys])
 | |
|     else:
 | |
|       return ",".join([urllib.quote(key, safe) + "," + urllib.quote(value[key], safe) for key in keys])
 | |
|   else:
 | |
|     return urllib.quote(value, safe)
 | |
| 
 | |
| 
 | |
| def _tostring_path(varname, value, explode, operator, safe=""):
 | |
|   joiner = operator
 | |
|   if type(value) == type([]):
 | |
|     if explode == "+":
 | |
|       return joiner.join([varname + "." + urllib.quote(x, safe) for x in value])
 | |
|     elif explode == "*":
 | |
|       return joiner.join([urllib.quote(x, safe) for x in value])
 | |
|     else:
 | |
|       return ",".join([urllib.quote(x, safe) for x in value])
 | |
|   elif type(value) == type({}):
 | |
|     keys = value.keys()
 | |
|     keys.sort()
 | |
|     if explode == "+":
 | |
|       return joiner.join([varname + "." + urllib.quote(key, safe) + joiner + urllib.quote(value[key], safe) for key in keys])
 | |
|     elif explode == "*":
 | |
|       return joiner.join([urllib.quote(key, safe) + joiner + urllib.quote(value[key], safe) for key in keys])
 | |
|     else:
 | |
|       return ",".join([urllib.quote(key, safe) + "," + urllib.quote(value[key], safe) for key in keys])
 | |
|   else:
 | |
|     if value:
 | |
|       return urllib.quote(value, safe)
 | |
|     else:
 | |
|       return ""
 | |
| 
 | |
| def _tostring_query(varname, value, explode, operator, safe=""):
 | |
|   joiner = operator
 | |
|   varprefix = ""
 | |
|   if operator == "?":
 | |
|     joiner = "&"
 | |
|     varprefix = varname + "=" 
 | |
|   if type(value) == type([]):
 | |
|     if 0 == len(value):
 | |
|       return ""
 | |
|     if explode == "+":
 | |
|       return joiner.join([varname + "=" + urllib.quote(x, safe) for x in value])
 | |
|     elif explode == "*":
 | |
|       return joiner.join([urllib.quote(x, safe) for x in value])
 | |
|     else:
 | |
|       return varprefix + ",".join([urllib.quote(x, safe) for x in value])
 | |
|   elif type(value) == type({}):
 | |
|     if 0 == len(value):
 | |
|       return ""
 | |
|     keys = value.keys()
 | |
|     keys.sort()
 | |
|     if explode == "+":
 | |
|       return joiner.join([varname + "." + urllib.quote(key, safe) + "=" + urllib.quote(value[key], safe) for key in keys])
 | |
|     elif explode == "*":
 | |
|       return joiner.join([urllib.quote(key, safe) + "=" + urllib.quote(value[key], safe) for key in keys])
 | |
|     else:
 | |
|       return varprefix + ",".join([urllib.quote(key, safe) + "," + urllib.quote(value[key], safe) for key in keys])
 | |
|   else:
 | |
|     if value:
 | |
|       return varname + "=" + urllib.quote(value, safe)
 | |
|     else:
 | |
|       return varname 
 | |
| 
 | |
| TOSTRING = {
 | |
|     "" : _tostring,
 | |
|     "+": _tostring,
 | |
|     ";": _tostring_query,
 | |
|     "?": _tostring_query,
 | |
|     "/": _tostring_path,
 | |
|     ".": _tostring_path,
 | |
|     }
 | |
| 
 | |
| 
 | |
| def expand(template, vars):
 | |
|   def _sub(match):
 | |
|     groupdict = match.groupdict()
 | |
|     operator = groupdict.get('operator')
 | |
|     if operator is None:
 | |
|       operator = ''
 | |
|     varlist = groupdict.get('varlist')
 | |
| 
 | |
|     safe = ""
 | |
|     if operator == '+':
 | |
|       safe = RESERVED
 | |
|     varspecs = varlist.split(",")
 | |
|     varnames = []
 | |
|     defaults = {}
 | |
|     for varspec in varspecs:
 | |
|       m = VAR.search(varspec)
 | |
|       groupdict = m.groupdict()
 | |
|       varname = groupdict.get('varname')
 | |
|       explode = groupdict.get('explode')
 | |
|       partial = groupdict.get('partial')
 | |
|       default = groupdict.get('default')
 | |
|       if default:
 | |
|         defaults[varname] = default
 | |
|       varnames.append((varname, explode, partial))
 | |
| 
 | |
|     retval = []
 | |
|     joiner = operator
 | |
|     prefix = operator
 | |
|     if operator == "+":
 | |
|       prefix = ""
 | |
|       joiner = ","
 | |
|     if operator == "?":
 | |
|       joiner = "&"
 | |
|     if operator == "":
 | |
|       joiner = ","
 | |
|     for varname, explode, partial in varnames:
 | |
|       if varname in vars:
 | |
|         value = vars[varname]
 | |
|         #if not value and (type(value) == type({}) or type(value) == type([])) and varname in defaults:
 | |
|         if not value and value != "" and varname in defaults:
 | |
|           value = defaults[varname]
 | |
|       elif varname in defaults:
 | |
|         value = defaults[varname]
 | |
|       else:
 | |
|         continue
 | |
|       retval.append(TOSTRING[operator](varname, value, explode, operator, safe=safe))
 | |
|     if "".join(retval):
 | |
|       return prefix + joiner.join(retval)
 | |
|     else:
 | |
|       return ""
 | |
| 
 | |
|   return TEMPLATE.sub(_sub, template)
 | 
