remove name from URLType, handle it separately in SimpleValueLabel + improve query argument handling
authorTero Marttila <terom@fixme.fi>
Mon, 09 Feb 2009 03:05:19 +0200
changeset 49 9b097385b463
parent 48 480adab03749
child 50 e4fbf480fbee
remove name from URLType, handle it separately in SimpleValueLabel + improve query argument handling
http.py
urltree.py
--- a/http.py	Mon Feb 09 01:17:20 2009 +0200
+++ b/http.py	Mon Feb 09 03:05:19 2009 +0200
@@ -99,6 +99,17 @@
         else :
             return ''
     
+    def get_arg (self, name, default=None) :
+        """
+            Get a single value for an argument with the given key, or the default if missing
+        """
+
+        if name in self.arg_dict :
+            return self.arg_dict[name][0]
+
+        else :
+            return default
+
     def get_args (self) :
         """
             Iterate over all available (key, value) pairs from the query string
--- a/urltree.py	Mon Feb 09 01:17:20 2009 +0200
+++ b/urltree.py	Mon Feb 09 03:05:19 2009 +0200
@@ -56,10 +56,10 @@
             key = match.group('key')
 
             # type
-            type = match.group("type")
+            type_name = match.group("type")
             
             # lookup type, None -> default
-            type = config.get_type(type)
+            type = config.get_type(type_name)
 
             # defaults?
             default = defaults.get(key)
@@ -72,7 +72,7 @@
                     default = type.parse(default)
 
             # build
-            return SimpleValueLabel(key, type, default)
+            return SimpleValueLabel(key, type_name, type, default)
         
         # static?
         match = StaticLabel.EXPR.match(mask)
@@ -219,12 +219,15 @@
 
     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, default) :
+    def __init__ (self, key, type_name, type, default) :
         """
-            The given key is the name of this label's value
+            The given key is the name of this label's value.
+
+            The given type_name is is None for the default type, otherwise the type's name. Type is a URLType.
         """
 
         # type
+        self.type_name = type_name
         self.type = type
 
         # store
@@ -254,7 +257,7 @@
     def __str__ (self) :
         return '{%s%s%s}' % (
             self.key, 
-            ':%s' % (self.type, ),  # XXX: omit if default
+            (':%s' % (self.type_name, ) if self.type_name else ''),
             '=%s' % (self.default, ) if self.default else '',
         )
 
@@ -263,13 +266,6 @@
         Handles the type-ness of values in the URL
     """
 
-    def _init_name (self, name) :
-        """
-            Initialize our .name attribute, called by URLConfig
-        """
-
-        self.name = name
-
     def test (self, value) :
         """
             Tests if the given value is valid for this type.
@@ -301,13 +297,6 @@
 
         abstract
 
-    def __str__ (self) :
-        """
-            Return a short string giving the name of this type, defaults to self.name
-        """
-
-        return self.name
- 
 class URLStringType (URLType) :
     """
         The default URLType, just plain strings.
@@ -315,9 +304,6 @@
         Note that this does not accept empty strings as valid
     """
 
-    def __init__ (self) :
-        super(URLStringType, self).__init__('str')
-
     def parse (self, value) :
         """
             Identitiy
@@ -342,8 +328,6 @@
             to specifiy maximum value
         """
 
-        super(URLIntegerType, self).__init__('int')
-
         self.negative = negative
         self.zero = zero
         self.max = max
@@ -386,10 +370,15 @@
         Global configuration relevant to all URLs. This can be used to construct a set of URLs and then create an
         URLTree out of them. Simply call the url_config() instace with the normal URL arguments (except, of course,
         config), and finally just pass the url_config to URLTree (it's iterable).
+
+        XXX: rename to URLFactory?
     """
 
     # built-in type codes
     BUILTIN_TYPES = {
+        # default - string
+        None    : URLStringType(),
+
         # string
         'str'   : URLStringType(),
 
@@ -397,16 +386,15 @@
         'int'   : URLIntegerType(),
     }
 
-    # init names
-    for name, type in BUILTIN_TYPES.iteritems() :
-        type._init_name(name)
-
-    def __init__ (self, type_dict=None, default_type='str') :
+    def __init__ (self, type_dict=None, ignore_extra_args=True) :
         """
             Create an URLConfig for use with URL
 
             If type_dict is given, it should be a dict of { type_names: URLType }, and they will be available for
-            type specifications in addition to the defaults.
+            type specifications in addition to the defaults. This will call type._init_name with the key, so do
+            *not* initialize the name yourself.
+
+            If ignore_extra_args is given, unrecognized query arguments will be ignored.
         """
 
         # build our type_dict
@@ -414,26 +402,18 @@
         
         # apply the given type_dict
         if type_dict :
-            # initialize names
-            for name, type in type_dict.iteritems() :
-                type._init_name(name)
-            
             # merge
             self.type_dict.update(type_dict)
 
         # init
-        self.default_type = default_type
+        self.ignore_extra_args = ignore_extra_args
         self.urls = []
         
     def get_type (self, type_name=None) :
         """
-            Lookup an URLType by type_name, None for default
+            Lookup an URLType by type_name, None for default.
         """
         
-        # default type?
-        if not type_name :
-            type_name = self.default_type
-        
         # lookup + return
         return self.type_dict[type_name]
 
@@ -537,6 +517,15 @@
        
         # then parse all query args
         for key, value in request.get_args() :
+            # unknown key?
+            if key not in self.query_args :
+                # ignore?
+                if self.config.ignore_extra_args :
+                    continue
+                
+                else :
+                    raise URLError("Unrecognized query argument: %r" % (key, ))
+
             # lookup spec
             type, default = self.query_args[key]