--- a/urltree.py Thu Feb 12 01:37:02 2009 +0200
+++ b/urltree.py Thu Feb 12 01:38:29 2009 +0200
@@ -252,7 +252,7 @@
A label that has a name and a simple string value
"""
- EXPR = re.compile(r'^\{(?P<key>[a-zA-Z_][a-zA-Z0-9_]*)(:(?P<type>[a-zA-Z_][a-zA-Z0-9_]*))?(=(?P<default>[^}]+))?\}$')
+ EXPR = re.compile(r'^\{(?P<key>[a-zA-Z_][a-zA-Z0-9_]*)(:(?P<type>[a-zA-Z_][a-zA-Z0-9_]*))?(=(?P<default>[^}]*))?\}$')
def __init__ (self, key, type_name, type, default) :
"""
@@ -324,6 +324,14 @@
abstract
+ def append (self, old_value, value) :
+ """
+ Handle multiple values for this type, by combining the given old value and new value (both from parse).
+
+ Defaults to raise an error
+ """
+
+ raise URLError("Multiple values for argument")
def build (self, obj) :
"""
@@ -332,11 +340,18 @@
abstract
+ def build_multi (self, obj) :
+ """
+ Return a list of string values for the given object value (as from parse/append).
+
+ Defaults to return [self.build(obj)]
+ """
+
+ return [self.build(obj)]
+
class URLStringType (URLType) :
"""
The default URLType, just plain strings.
-
- Note that this does not accept empty strings as valid
"""
def parse (self, value) :
@@ -347,9 +362,6 @@
return value
def build (self, obj) :
- if not obj :
- raise ValueError("String must not be empty")
-
return str(obj)
class URLIntegerType (URLType) :
@@ -400,6 +412,20 @@
return unicode(self._validate(obj))
+class URLListType (URLType) :
+ """
+ A list of strings
+ """
+
+ def parse (self, value) :
+ return [value]
+
+ def append (self, old_value, value) :
+ return old_value + value
+
+ def build_multi (self, obj) :
+ return obj
+
class URLConfig (object) :
"""
Global configuration relevant to all URLs. This can be used to construct a set of URLs and then create an
@@ -419,6 +445,9 @@
# integer
'int' : URLIntegerType(),
+
+ # list of strs
+ 'list' : URLListType(),
}
def __init__ (self, type_dict=None, ignore_extra_args=True) :
@@ -599,8 +628,14 @@
# otherwise, fail
raise URLError("No value given for required argument: %r" % (key, ))
- # set key
- kwargs[key] = value
+ # already have a value?
+ if key in kwargs :
+ # append to old value
+ kwargs[key] = type.append(kwargs[key], value)
+
+ else :
+ # set key
+ kwargs[key] = value
# then check all query args
for key, (type, default) in self.query_args.iteritems() :
@@ -647,10 +682,10 @@
# join
url = '/'.join(segment for is_default, segment in segments if segment is not None)
- # build query args
- query_args = dict((key, type.build(values[key])) for key, (type, default) in self.query_args.iteritems() if key in values and values[key] is not None)
+ # build query args as { key -> [value] }
+ query_args = dict((key, type.build_multi(values[key])) for key, (type, default) in self.query_args.iteritems() if key in values and values[key] is not None)
- return "%s%s" % (url, '?%s' % ('&'.join('%s=%s' % tup for tup in query_args.iteritems())) if query_args else '')
+ return "%s%s" % (url, '?%s' % ('&'.join('%s=%s' % (key, value) for value in values for key, values in query_args.iteritems())) if query_args else '')
def __str__ (self) :
return '/'.join(str(label) for label in self.label_path)