svv/ext/urltree.py
author Tero Marttila <terom@fixme.fi>
Tue, 11 Jan 2011 01:12:50 +0200
changeset 57 7a48e9d96ec8
parent 45 e3001377e9dc
permissions -rw-r--r--
items: fix NewOrderView
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     1
"""
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
     2
    Tree-based URL mapping.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
     3
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
     4
    urltree is used to construct a tree-like structure of URL handlers, and to match a given URL against the tree,
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
     5
    returning the matching handler.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
     6
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
     7
    URLs are handled as a sequence of labels, separated by slashes (/). Thus, an URL like /foo/bar/baz would be handled
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
     8
    as a list of three labels:
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
     9
        ['foo', 'bar', 'baz']
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    10
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    11
    The URL handler rules are constructed as a sequence of Labels, which then match and evaluate URL segments.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    12
    
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    13
        StaticLabel just matches a pre-defined/constant segment, and is used to route URLs through the URL tree. 
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    14
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    15
        ValueLabel matches segments dynamically, capturing them as a typed value. It also supports default values.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    16
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    17
    urltree also handles building URL strings for a given handler, and a set of values.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    18
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    19
    urltree can also handle query-string parameters (i.e. GET params).
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    20
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    21
"""
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    22
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    23
import re
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    24
import os.path
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    25
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    26
import werkzeug
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    27
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    28
class URLError (Exception) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    29
    """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    30
        Error with an URL definition, parsing, or value handling.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    31
    """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    32
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    33
    pass
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    34
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    35
class URLRuleError (URLError) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    36
    """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    37
        Error in URLTree structure definition.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    38
    """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    39
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    40
class URLMatchError (URLError) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    41
    """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    42
        Error looking up the URL against our URLTree.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    43
    """
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    44
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    45
class URLValueError (URLError) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    46
    """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    47
        Error parsing an URL segment's value via URLType.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    48
    """
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    49
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    50
    pass
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    51
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    52
class URLBuildError (URLError) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    53
    """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    54
        Error re-constructing an outgoing URL.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    55
    """
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    56
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    57
class Label (object) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    58
    """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    59
        Abstract base class for URL segment-matching rules.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    60
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    61
        A Label subclass is constructed by parse()ing a text-form URL segment spec (== label), and knows how to do a
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    62
        yes/value/no match() against an URL segment, as well as re-build() the URL segment for the matched value.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    63
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    64
        XXX: rename to URLRuleLabel or something like that
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    65
    """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    66
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    67
    @staticmethod
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    68
    def parse (spec, defaults, config) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    69
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    70
            Parse the given label-spec, and return an appropriate Label subclass instance.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    71
                
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    72
                spec            - the rule specification as text
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    73
                defaults        - externally supplied { key: default } dict of default values
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    74
                config          - URLConfig instance to use for constructed Label
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    75
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    76
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    77
        # empty/root?
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    78
        if not spec :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    79
            return EmptyLabel()
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    80
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    81
        # construct subclass instance by matching against regexps
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    82
        for label_type in (
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    83
            ValueLabel,
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    84
            StaticLabel,
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    85
        ) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    86
            # test
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    87
            match = label_type.PARSE_RE.match(spec)
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    88
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    89
            if match :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    90
                return label_type.parse(match, defaults, config)
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    91
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    92
        # invalid
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    93
        raise URLError("Unrecognized label: %r" % (spec, ))
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    94
    
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    95
    def match (self, value=None) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    96
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    97
            Match this label against the given URL segment, returning one of :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    98
            
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
    99
                * True to match without a value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   100
                * False/None to not match, and continue looking
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   101
                * a (key, value, label, is_default) capture-tuple to capture a named value from the URL segment
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   102
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   103
                value       - a segment from the URL as text, or None to force default value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   104
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   105
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   106
        raise NotImplemented()
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   107
    
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   108
    def build (self, values) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   109
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   110
            Re-construct this label, using values from the supplied { key: value } dict if needed.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   111
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   112
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   113
        raise NotImplemented()
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   114
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   115
    def build_default (self, values) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   116
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   117
            Return an (is_default, value) tuple
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   118
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   119
            XXX: used internally by build()?
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   120
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   121
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   122
        raise NotImplemented()
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   123
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   124
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   125
class EmptyLabel (Label) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   126
    """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   127
        An empty label, which matches empty URL segments, i.e. '//foo' or '/'
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   128
    """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   129
    
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   130
    def __eq__ (self, other) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   131
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   132
            Just compares type
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   133
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   134
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   135
        return isinstance(other, EmptyLabel)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   136
    
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   137
    def match (self, value=None) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   138
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   139
            Matches empty segment.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   140
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   141
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   142
        # no default
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   143
        if value is None :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   144
            return False
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   145
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   146
        # only empty segments
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   147
        if value == '' :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   148
            return True
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   149
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   150
        return False
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   151
    
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   152
    def build (self, values) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   153
        return ''
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   154
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   155
    def build_default (self, values) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   156
        return (False, '')
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   157
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   158
    def __str__ (self) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   159
        return ''
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   160
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   161
class StaticLabel (Label) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   162
    """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   163
        A simple literal Label, used to match fixed segments in the URL.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   164
    """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   165
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   166
    PARSE_RE = re.compile(r'^(?P<name>[a-zA-Z0-9_.-]+)$')
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   167
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   168
    @classmethod
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   169
    def parse (cls, match, defaults, config) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   170
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   171
            Construct and return a new instance from the given PARSE_RE match
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   172
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   173
            
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   174
        # use name as required segment value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   175
        return cls(match.group('name'))
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   176
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   177
    def __init__ (self, name) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   178
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   179
            The given name is the literal name of this label
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   180
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   181
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   182
        self.name = name
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   183
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   184
    def __eq__ (self, other) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   185
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   186
            Compares names
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   187
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   188
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   189
        return isinstance(other, StaticLabel) and self.name == other.name
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   190
    
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   191
    def match (self, value=None) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   192
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   193
            Match exactly -> True
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   194
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   195
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   196
        # no defaults
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   197
        if value is None :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   198
            return False
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   199
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   200
        # match name
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   201
        elif value == self.name :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   202
            return True
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   203
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   204
        # fail
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   205
        else :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   206
            return False
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   207
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   208
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   209
    def build (self, values) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   210
        return self.name
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   211
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   212
    def build_default (self, values) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   213
        return (False, self.name)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   214
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   215
    def __str__ (self) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   216
        return self.name
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   217
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   218
class ValueLabel (Label) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   219
    """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   220
        A label with a key and a typed value
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   221
    """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   222
    
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   223
    # / "{" <key> [ ":" <type> ] [ "=" [ <default> ] ] "}" /
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   224
    PARSE_RE = re.compile(r'^\{(?P<key>[a-zA-Z_][a-zA-Z0-9_]*)(:(?P<type>[a-zA-Z_][a-zA-Z0-9_]*))?(=(?P<default>[^}]*))?\}$')
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   225
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   226
    @classmethod
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   227
    def parse (cls, match, defaults, config) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   228
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   229
            Construct and return a new instance from the given PARSE_RE match
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   230
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   231
 
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   232
        # value name
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   233
        key = match.group('key')
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   234
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   235
        # value type, or None
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   236
        type_name = match.group("type")
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   237
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   238
        # lookup URLType, None -> default type
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   239
        type = config.get_type(type_name)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   240
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   241
        # get default value from dict, or None
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   242
        default = defaults.get(key)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   243
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   244
        if not default :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   245
            # default vlaue from expr?
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   246
            default = match.group('default')
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   247
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   248
            if default :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   249
                # parse text-form default to actual value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   250
                # XXX: is this "" or None if match is for '{foo=}' ?
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   251
                default = type.parse(default)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   252
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   253
        # build
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   254
        return cls(key, type, default, type_name)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   255
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   256
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   257
    def __init__ (self, key, type, default, type_name) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   258
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   259
            The given key is the name of this label's value.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   260
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   261
            The given type_name is is None for the default type, otherwise the type's name. Type is a URLType.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   262
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   263
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   264
                key         - the name of this label's value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   265
                type        - the URLType used to parse/build the value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   266
                default     - default for value, if no value is given in URL, or None for no default (value required)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   267
                type_name   - parsed name for the type; used for debugging
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   268
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   269
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   270
        # store
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   271
        self.key = key
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   272
        self.default = default
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   273
 
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   274
        # type
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   275
        self.type_name = type_name
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   276
        self.type = type
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   277
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   278
    def __eq__ (self, other) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   279
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   280
            Compares keys
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   281
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   282
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   283
        return isinstance(other, ValueLabel) and self.key == other.key
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   284
    
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   285
    def match (self, seg=None) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   286
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   287
            Match segment -> (key, value, type, is_default)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   288
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   289
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   290
        if seg is None and self.default is not None :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   291
            # default value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   292
            return self.key, self.default, self.type, True
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   293
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   294
        # we don't have a default value, so don't match partial URLs
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   295
        elif not seg :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   296
            return False
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   297
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   298
        # test against type's syntax
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   299
        elif not self.type.test(seg) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   300
            return False
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   301
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   302
        else :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   303
            # convert with type
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   304
            value = self.type.parse(seg)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   305
            
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   306
            # False == non-default value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   307
            return self.key, value, self.type, False
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   308
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   309
    def build (self, values) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   310
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   311
            Return either the assigned value from values, our default value, or raise an error
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   312
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   313
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   314
        # just proxy to build_default
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   315
        return self.build_default(values)[1]
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   316
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   317
    def build_default (self, values) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   318
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   319
            Check if we have a value in values, and return based on that.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   320
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   321
 
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   322
        # state
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   323
        is_default = False
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   324
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   325
        # value given?
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   326
        if self.key not in values or values[self.key] is None :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   327
            if self.default is None :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   328
                # no value given for required label
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   329
                raise URLBuildError("No value given for label %r" % (self.key, ))
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   330
            
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   331
            # use default
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   332
            else :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   333
                is_default = True
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   334
                value = self.default
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   335
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   336
        else :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   337
            # lookup the value to use
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   338
            value = values[self.key]
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   339
            
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   340
            # smart-match against default value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   341
            # XXX: would it be better not to omit it as a default value in this case?
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   342
            is_default = bool(value == self.default)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   343
        
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   344
        # convert value to str
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   345
        value = self.type.build(value)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   346
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   347
        # return
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   348
        return (is_default, value)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   349
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   350
    def __str__ (self) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   351
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   352
            Pretty-format back into parsed form.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   353
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   354
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   355
        return '{%s%s%s}' % (
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   356
            self.key, 
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   357
            (':%s' % (self.type_name, ) if self.type_name is not None else ''),
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   358
            '=%s' % (self.default, ) if self.default is not None else '',
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   359
        )
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   360
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   361
class QueryItem (object) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   362
    """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   363
        Like a normal URL Label, except for dealing with query-string arguments.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   364
    """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   365
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   366
    @classmethod
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   367
    def parse (cls, spec, defaults, config) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   368
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   369
            Construct and return a new instance from the given spec
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   370
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   371
 
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   372
        # parse default value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   373
        if '=' in spec :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   374
            # default value, might be empty
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   375
            spec, default_spec = spec.split('=')
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   376
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   377
        else :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   378
            # no default, value required
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   379
            default_spec = None
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   380
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   381
        # parse type
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   382
        if ':' in spec :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   383
            # use named type
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   384
            spec, type_name = spec.split(':')
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   385
        else :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   386
            # use default type
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   387
            type_name = None
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   388
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   389
        # name for value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   390
        key = spec
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   391
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   392
        # URLType
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   393
        type = config.get_type(type_name)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   394
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   395
        if key in defaults :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   396
            # default value from external defaults dict
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   397
            default = defaults[key]
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   398
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   399
        elif default_spec :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   400
            # given default value spec
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   401
            default = type.parse(default_spec)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   402
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   403
        elif default_spec is not None :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   404
            # XXX: no default value, but not required either... silly
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   405
            default = ''
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   406
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   407
        else :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   408
            # no default value, required
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   409
            default = None
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   410
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   411
        # build
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   412
        return cls(key, type, default)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   413
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   414
    def __init__ (self, key, type, default) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   415
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   416
            The given key is the name of this label's value.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   417
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   418
            The given type_name is is None for the default type, otherwise the type's name. Type is a URLType.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   419
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   420
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   421
                key         - the name of this label's value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   422
                type        - the URLType used to parse/build the value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   423
                default     - default for value, if no value is given in URL, or None for no default (value required)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   424
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   425
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   426
        # store
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   427
        self.key = key
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   428
        self.type = type
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   429
        self.default = default
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   430
 
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   431
    def match (self, arg=None) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   432
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   433
            Parse value from given query-string argument for this key
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   434
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   435
                arg         - the list of query-string values given, or None for missing value.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   436
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   437
            Returns value to use, or None to omit.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   438
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   439
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   440
        if not arg :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   441
            if self.default is None :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   442
                # no default value!
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   443
                raise URLValueError("No value given for query string param: ?%s=..." % (self.key, ))
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   444
            
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   445
            elif self.default == '' :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   446
                # XXX: omit
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   447
                return None
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   448
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   449
            else :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   450
                # use default value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   451
                return self.default
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   452
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   453
        # parse with our type
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   454
        value = None
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   455
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   456
        for value_spec in arg :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   457
            if value is None :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   458
                # parse first
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   459
                value = self.type.parse(value_spec)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   460
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   461
            else :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   462
                # parse multiple
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   463
                value = self.type.append(value, self.type.parse(value_spec))
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   464
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   465
        # ok
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   466
        return value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   467
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   468
    def build (self, values) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   469
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   470
            Build and return list of query-string values to pass for this argument, or None to omit.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   471
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   472
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   473
        if self.key not in values :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   474
            if self.default is None :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   475
                # fail
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   476
                raise URLBuildError("No value given for query string arugment %r" % (self.key, ))
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   477
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   478
            else :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   479
                # omit, and use default value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   480
                return None
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   481
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   482
        else :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   483
            # lookup our value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   484
            value = values[self.key]
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   485
            
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   486
            if value is not None :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   487
                # map to values
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   488
                return self.type.build_multi(value)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   489
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   490
            else :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   491
                # omit
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   492
                return None
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   493
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   494
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   495
class URLType (object) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   496
    """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   497
        Handles the type-ness of values in the URL
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   498
    """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   499
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   500
    def test (self, value) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   501
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   502
            Tests if the given value is accepted for this type.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   503
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   504
            Defaults to calling parse(), and returning False on errors, True otherwise
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   505
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   506
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   507
        try :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   508
            self.parse(value)
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   509
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   510
        # XXX: change to URLValueError to not swallow bugs
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   511
        except Exception :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   512
            return False
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   513
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   514
        else :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   515
            return True
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   516
    
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   517
    def parse (self, seg) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   518
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   519
            Parse the given URL segment text, which was tested earlier with test(), and return the value object.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   520
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   521
            Raise an URLValueError to reject the value via the default test() implementation.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   522
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   523
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   524
        raise NotImplementedError()
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   525
    
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   526
    def append (self, old_value, value) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   527
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   528
            Handle multi-valued values, by combining the given previously parse()'d value and newly parse()'d value.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   529
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   530
            Defaults to raise an error.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   531
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   532
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   533
        raise URLValueError("Multiple values given")
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   534
   
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   535
    def build (self, value) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   536
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   537
            Reverse of parse(), return an URL segment built from the given object value
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   538
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   539
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   540
        raise NotImplementedError()
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   541
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   542
    def build_multi (self, value) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   543
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   544
            Return a list of URL segments for the given object value (as from parse/append), for multi-value types.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   545
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   546
            Defaults to return [self.build(obj)]
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   547
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   548
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   549
        return [self.build(value)]
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   550
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   551
class URLStringType (URLType) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   552
    """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   553
        The default URLType, just plain strings.
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   554
        
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   555
        XXX: handle unicode here, or assume URL is unicode?
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   556
    """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   557
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   558
    def parse (self, seg) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   559
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   560
            Identitiy
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   561
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   562
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   563
        return unicode(seg)
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   564
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   565
    def build (self, value) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   566
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   567
            Return value's string representation for URL
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   568
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   569
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   570
        return unicode(value)
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   571
    
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   572
class URLIntegerType (URLType) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   573
    """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   574
        A URLType for simple int's, with some constraing checking
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   575
    """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   576
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   577
    def __init__ (self, allow_negative=True, allow_zero=True, max=None) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   578
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   579
            Pass in allow_negative=False to disallow negative numbers, allow_zero=False to disallow zero, or non-zero
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   580
            max to specifiy maximum value
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   581
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   582
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   583
        self.allow_negative = allow_negative
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   584
        self.allow_zero = allow_zero
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   585
        self.max = max
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   586
    
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   587
    def _validate (self, value) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   588
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   589
            Test to make sure value fits our criteria
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   590
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   591
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   592
        # negative?
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   593
        if not self.allow_negative and value < 0 :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   594
            raise URLValueError("value is negative")
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   595
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   596
        # zero?
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   597
        if not self.allow_zero and value == 0 :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   598
            raise URLValueError("value is zero")
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   599
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   600
        # max?
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   601
        if self.max is not None and value > self.max :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   602
            raise URLValueError("value is too large: %d" % value)
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   603
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   604
        return value
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   605
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   606
    def parse (self, seg) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   607
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   608
            Convert str -> int
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   609
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   610
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   611
        try :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   612
            value = int(seg)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   613
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   614
        except ValueError, ex :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   615
            # reject
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   616
            raise URLValueError(ex)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   617
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   618
        # validate
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   619
        return self._validate(value)
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   620
    
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   621
    def build (self, obj) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   622
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   623
            Convert int -> str
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   624
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   625
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   626
        return unicode(self._validate(obj))
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   627
    
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   628
class URLListType (URLStringType) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   629
    """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   630
        A list of strings
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   631
    """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   632
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   633
    def parse (self, seg) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   634
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   635
            URL segments are just parsed into single-item lists.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   636
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   637
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   638
        return [super(URLListType, self).parse(seg)]
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   639
    
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   640
    def append (self, old_value, value) :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   641
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   642
            Accumulate values in list.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   643
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   644
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   645
        # combine lists
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   646
        return old_value + value
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   647
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   648
    def build_multi (self, value) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   649
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   650
            Return as a list of build()'d values.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   651
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   652
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   653
        return [super(URLListType, self).build(item) for item in value]
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   654
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   655
class URLConfig (object) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   656
    """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   657
        Shared configuration relevant to a set of constructed URLRules.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   658
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   659
        This can be used as a factory to accumulate constructed URLRules, and then create an URLTree out of them.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   660
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   661
        Simply __call__ the URLConfig() instance with the normal URLRule() *args (except, of course, config=), and finally
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   662
        just pass the URLConfig() to URLTree() - it's iter()able.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   663
    """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   664
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   665
    # built-in type codes
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   666
    BUILTIN_TYPES = {
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   667
        # default - string
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   668
        None    : URLStringType(),
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   669
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   670
        # string
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   671
        'str'   : URLStringType(),
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   672
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   673
        # integer
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   674
        'int'   : URLIntegerType(),
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   675
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   676
        # list of strs
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   677
        'list'  : URLListType(),
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   678
    }
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   679
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   680
    def __init__ (self, type_dict=None, reject_extra_args=None) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   681
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   682
            Create an URLConfig for use with URLTree/URLs.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   683
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   684
                type_dict               - (optional) { type_name: URLType } dict of additional URLTypes to make
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   685
                                          available for use in URLRules. This will take care of ._init_name().
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   686
                                          Use None as a key to change the default URLType.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   687
                reject_extra_args       - instead of ignoring unrecognized query arguments in matched URLs, reject them
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   688
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   689
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   690
        # our type_dict
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   691
        self.type_dict = self.BUILTIN_TYPES.copy()
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   692
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   693
        if type_dict :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   694
            # merge
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   695
            self.type_dict.update(type_dict)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   696
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   697
        # init
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   698
        self.ignore_extra_args = not(reject_extra_args)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   699
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   700
        # accumulated URLRules
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   701
        self.urls = []
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   702
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   703
    def get_type (self, type_name=None) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   704
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   705
            Lookup an URLType by type_name, None for default type.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   706
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   707
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   708
        # lookup + return
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   709
        return self.type_dict[type_name]
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   710
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   711
    def __call__ (self, *args, **kwargs) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   712
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   713
            Return new URLRule with this config and the given args, adding it to our list of urls
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   714
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   715
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   716
        # build
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   717
        url = URLRule(self, *args, **kwargs)
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   718
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   719
        # store
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   720
        self.urls.append(url)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   721
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   722
        # return
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   723
        return url
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   724
    
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   725
    def __iter__ (self) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   726
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   727
            Returns all defined URLRules
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   728
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   729
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   730
        return iter(self.urls)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   731
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   732
class URLRule (object) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   733
    """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   734
        A set of Labels defining a path to a handler in the URLTree, parsed from a string-form URL-spec.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   735
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   736
        XXX: also handles query_args, spec that properly...
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   737
    """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   738
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   739
    def __init__ (self, config, url_spec, handler, **defaults) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   740
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   741
            Create an URL using the given URLConfig, with the given url mask, handler, and default values.
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   742
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   743
                config          - the URLConfig() used for this rule
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   744
                url_spec        - a string-form sequence of Label rules to parse
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   745
                                  Should be rooted, i.e. start with a '/'
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   746
                handler         - the target of this URLRule(), returned as the result of the lookup
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   747
                **defaults      - additional default values. Can be used to specify/override the default values in the
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   748
                                  url_spec for complex values, or just extra args to pass through.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   749
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   750
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   751
        # store
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   752
        self.config = config
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   753
        self.url_spec = url_spec
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   754
        self.handler = handler
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   755
        self.defaults = defaults
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   756
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   757
        # query string spec
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   758
        self.query_items = dict()
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   759
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   760
        # remove prepending root /
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   761
        url_spec = url_spec.lstrip('/')
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   762
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   763
        # parse any query string
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   764
        # XXX: conflicts with regexp syntax
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   765
        if '/?' in url_spec :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   766
            url_spec, query_spec = url_spec.split('/?')
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   767
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   768
        else :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   769
            query_spec = None
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   770
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   771
        # parse the spec into a sequence of Labels
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   772
        self.label_path = [Label.parse(label_spec, defaults, config) for label_spec in url_spec.split('/')]
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   773
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   774
        # parse query args
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   775
        if query_spec :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   776
            for item_spec in query_spec.split('&') :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   777
                # parse spec into QueryItem
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   778
                query_item = QueryItem.parse(item_spec, defaults, config)
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   779
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   780
                # store, case-insensitive
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   781
                self.query_items[query_item.key.lower()] = query_item
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   782
         
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   783
    def get_label_path (self) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   784
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   785
            Returns the Label-path for this URLRule.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   786
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   787
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   788
        # copy self.label_path
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   789
        return list(self.label_path)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   790
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   791
    def evaluate (self, url_values, query_args) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   792
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   793
            Process the set of argument matched against this URLRule, both those values captured from the URL by
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   794
            Labels, and any incoming query string arguments:
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   795
            
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   796
                url_values          - a [ (key, value, type, is_default) ] sequence of capture-tuples values from URL segments/labels
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   797
                query_args          - a [ (key, [ value ] ] sequence of query string arguments. This will be mutated!
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   798
            
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   799
            Returns the parsed set of arguments, and the remaining query string arguments:
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   800
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   801
                return (
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   802
                    args            - a { key: value } dict of label and query string values, suitable for passing to
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   803
                                      handler function as keyword arguments
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   804
                    qargs           - a [ (key, [ value ] ] sequence of remaining query-string arguments not included
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   805
                                      in kwargs
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   806
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   807
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   808
        # convert url_values to dict for lookup
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   809
        url_values = dict((key, (value, type, is_default)) for key, value, type, is_default in url_values)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   810
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   811
        # collect a list of (key, value, is_default) tuples to later apply
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   812
        values = []
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   813
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   814
        # start with the explicitly supplied defaults
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   815
        # these may actually include additional arguments to be passed through to the handler
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   816
        for key, value in self.defaults.iteritems() :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   817
            values.append((key, value, True))
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   818
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   819
        # then add all the label values matched from the URL
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   820
        for key, (value, type, is_default) in url_values.iteritems() :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   821
            values.append((key, value, is_default))
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   822
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   823
        # then add in query args
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   824
        for key, value_list in query_args :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   825
            # case-insensitive
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   826
            key = key.lower()
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   827
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   828
            if key in self.query_items :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   829
                # defined as a QueryItem
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   830
                query_item = self.query_items[key]
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   831
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   832
                # parse as list/value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   833
                value = query_item.match(value_list)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   834
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   835
            # override URL label values if they were parsed as implicit defaults
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   836
            elif key in url_values :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   837
                old_value, type, is_default = url_values[key]
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   838
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   839
                if not is_default :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   840
                    # XXX: ignore extra value as per original implementation
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   841
                    continue
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   842
                
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   843
                # parse into value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   844
                value = None
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   845
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   846
                for value_spec in value_list :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   847
                    if value is None :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   848
                        # parse
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   849
                        value = type.parse(value_spec)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   850
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   851
                    else :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   852
                        # multi-value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   853
                        # XXX: this will usually fail, we can't really mix these very well
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   854
                        value = type.append(value, type.parse(value_spec))
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   855
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   856
            # unknown, ignore
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   857
            else :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   858
                continue
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   859
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   860
            # apply
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   861
            values.append((key, value, False))
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   862
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   863
        # outgoing args
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   864
        args = {}
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   865
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   866
        # args set to default value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   867
        default_args = set()
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   868
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   869
        # apply values
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   870
        for key, value, is_default in values :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   871
            # fresh value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   872
            if key not in args :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   873
                # store
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   874
                args[key] = value
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   875
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   876
                if is_default :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   877
                    default_args.add(key)
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   878
            
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   879
            # default value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   880
            elif key in args and key in default_args :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   881
               # replace default value with more specific value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   882
                args[key] = value
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   883
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   884
                if not is_default :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   885
                    default_args.remove(key)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   886
            
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   887
            # existing value
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   888
            else :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   889
                raise URLValueError("Multiple values given for param: %s" % (key, ))
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   890
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   891
        # then check for missing query_items
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   892
        for key, query_item in self.query_items.iteritems() :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   893
            # skip those already parsed
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   894
            if key in args :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   895
                continue
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   896
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   897
            # apply default
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   898
            value = query_item.match(None)
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   899
            
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   900
            if value is not None :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   901
                # set
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   902
                args[key] = value
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   903
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   904
        # remaining qargs not handled
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   905
        qargs = [(key, values) for key, values in query_args if key not in args]
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   906
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   907
        # ok
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   908
        return args, qargs
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   909
    
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   910
    def build (self, **values) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   911
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   912
            Build an absolute URL from our URLTree's root pointing to this target, with the given values embedded.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   913
            Default values are left off if they are at the end of the URL.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   914
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   915
            Values given as None are ignored.
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   916
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   917
            Returns (
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   918
                * the absolute URL from our URLTree's root to this URLRule as a str
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   919
                * query args for URL as a [ (key, [value]) ] list
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   920
            )
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   921
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   922
            # XXX: reject unrecognized values
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   923
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   924
        
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   925
        # root
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   926
        segments = [(False, '')] 
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   927
        
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   928
        # collect our Label-path's with values as a list of (is_default, segment) tuples
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   929
        segments += [label.build_default(values) for label in self.label_path]
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   930
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   931
        # optimize by trimming None/default items off the end
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   932
        for is_default, segment in segments[::-1] :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   933
            if segment is None or is_default :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   934
                segments.pop(-1)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   935
            
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   936
            else :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   937
                break
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   938
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   939
        # should have root left at least
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   940
        assert segments
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   941
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   942
        # join
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   943
        url = '/'.join(segment for is_default, segment in segments)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   944
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   945
        # build query args as { key -> [value] }
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   946
        qargs = [
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   947
            (
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   948
                key, query_item.build(values)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   949
            ) for key, query_item in self.query_items.iteritems()
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   950
        ]
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   951
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   952
        # filter
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   953
        qargs = [(key, values) for key, values in qargs if values is not None]
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   954
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   955
        return url, qargs
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   956
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   957
    def __str__ (self) :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   958
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   959
            Format pretty representation
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   960
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   961
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   962
        return '/'.join(str(label) for label in self.label_path)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   963
    
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   964
    def __repr__ (self) :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   965
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   966
            Format debug representation
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   967
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   968
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   969
        return "URL(%r, %r)" % (str(self), self.handler)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   970
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   971
class URLNode (object) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   972
    """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   973
        A Node in the URLTree structure, with the Label that it corresponds to.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   974
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   975
        Stores the set of URLNodes that exist below this, and optionally the URLRule this node maps to.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   976
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   977
        Used by URLTree to resolve an incoming URL.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   978
    """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   979
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   980
    def __init__ (self, parent, label, url_rule=None) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   981
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   982
            Initialize with the given parent and label, empty children dict
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   983
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   984
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   985
                parent      - the URLNode above this node, or None for root. Used to build() URL string
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   986
                label       - the Label matched by this URLNode
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   987
                url_rule    - the URLRule this Node maps to; set later using add_url() with an empty label_path
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   988
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   989
        
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   990
        # store
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   991
        self.parent = parent
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   992
        self.label = label
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   993
        self.url = None
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
   994
        
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   995
        # list of child URLNodes
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   996
        self.children = []
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   997
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   998
    def _build_child (self, label) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   999
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1000
            Build, insert and return a new child Node that maps from this Node via the given Label.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1001
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1002
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1003
        # build new child
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1004
        child = URLNode(self, label)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1005
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1006
        # add to children
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1007
        self.children.append(child)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1008
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1009
        # return
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1010
        return child
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1011
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1012
    def set_url (self, url) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1013
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1014
            Set the given URLRule as our mapped target (i.e. corresponds directly to this Node).
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1015
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1016
            Fails if we already have a mapped URLRule, since we can't have more than one.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1017
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1018
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1019
        if self.url :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1020
            raise URLRuleError(url, "node already has an URLRule mapped")
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1021
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1022
        # set
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1023
        self.url = url
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1024
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1025
    def add_url (self, url, label_path) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1026
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1027
            Insert an URLRule into the tree, using recursion to process the given label path, creating new URLNodes as needed.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1028
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1029
                url         - the URLRule we are storing in the tree
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1030
                label_path  - the path of Labels to the URLRule from this Node down
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1031
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1032
            If label_path is empty (len zero, or [EmptyLabel]), then the given url is mapped from this Node using set_url().
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1033
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1034
        
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1035
        # resolves to this node?
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1036
        # XXX: earlier, this was just anywhere, but that would mess up '/foo/bar//quux' def...
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1037
        if not label_path or (len(label_path) == 1 and isinstance(label_path[0], EmptyLabel)) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1038
            self.set_url(url)
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1039
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1040
        else :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1041
            # pop child's label from label_path
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1042
            child_label = label_path.pop(0)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1043
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1044
            # look for the child to recurse into
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1045
            child = None
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1046
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1047
            # look for an existing child with that label
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1048
            for child in self.children :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1049
                if child.label == child_label :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1050
                    # found, use this
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1051
                    break
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1052
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1053
            else :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1054
                # build and append a new child
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1055
                child = self._build_child(child_label)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1056
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1057
            # recurse to handle the rest of the label_path
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1058
            child.add_url(url, label_path)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1059
    
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1060
    def match (self, url_segments) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1061
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1062
            Locate and return the URLRule object corresponding to the given sequence of URL segments value under this node.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1063
            
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1064
            Return a (URLRule, [ LabelValue ] ) tuple, containing the matched URLRule, and all captured values from the URL.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1065
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1066
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1067
        # determine value to use
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1068
        value = None
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1069
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1070
        # label_path ends at this node
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1071
        # XXX: earlier this was just startswith, and would have matched '/foo/quux//bar/asdf' against '/foo/quux' - not sure if desired
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1072
        # XXX: always accept trailing / ?
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1073
        if not url_segments or (len(url_segments) == 1 and not url_segments[0]) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1074
            # the search ends at this node
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1075
            if self.url :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1076
                # this URL is the shortest match
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1077
                return (self.url, [])
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1078
            
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1079
            elif not self.children :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1080
                # incomplete URL
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1081
                raise URLMatchError("No URLRule found for URL")
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1082
            
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1083
            else :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1084
                # apply default value, i.e. Label.match(None), and continue recursing
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1085
                segment = None
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1086
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1087
        else :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1088
            # pop the next URL segment from the label path as the segments to match against our next 
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1089
            segment = url_segments.pop(0)
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1090
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1091
        # return one match...
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1092
        match = value = None
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1093
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1094
        # recurse through our children, DFS
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1095
        for child in self.children :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1096
            # match URL segment against next-down Label rule
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1097
            match_value = child.label.match(segment)
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1098
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1099
            if match_value is True :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1100
                # capture without value
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1101
                pass
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1102
 
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1103
            elif not match_value :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1104
                # skip those that don't match at all
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1105
                continue
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1106
             
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1107
            # match() gave a capture-tuple
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1108
            else :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1109
                # match_value is (key, value, type, is_default)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1110
                value = match_value
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1111
            
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1112
            # already found a match? :/
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1113
            if match :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1114
                # matches against multiple URLRules
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1115
                # XXX: just return first defined rule instead?
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1116
                # XXX: include troublesome nodes in error to aid debugging
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1117
                raise URLMatchError("Ambiguous URL: %s <-> %s" % (match, child))
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1118
            
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1119
            else :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1120
                # ok, but continue looking to make sure there's no ambiguous URLs
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1121
                match = child
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1122
            
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1123
        # found something?
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1124
        if not match :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1125
            # 404, kind of
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1126
            raise URLMatchError("URL not found: %s -> %s + %s" % (self.get_url(), segment, '/'.join(str(seg) for seg in url_segments)))
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1127
                    
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1128
        # recurse into the match using the remaining segments to get the rest of the values
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1129
        url, url_values = match.match(url_segments)
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1130
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1131
        # captured a value?
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1132
        if value is not None :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1133
            # add it to the set of values captured below us
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1134
            url_values.append(value)
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1135
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1136
        # return the match
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1137
        return url, url_values
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1138
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1139
    def get_url (self) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1140
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1141
            Returns the URLRule spec leading to this node, by iterating over our parents.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1142
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1143
        
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1144
        # URL segments in reverse order, ending with a /
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1145
        segments = ['']
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1146
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1147
        # start with ourself
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1148
        node = self
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1149
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1150
        # iterate up to root
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1151
        while node :
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1152
            # URLRule spec
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1153
            spec = str(node.label)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1154
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1155
            segments.append(spec)
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1156
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1157
            node = node.parent
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1158
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1159
        # reverse
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1160
        segments.reverse()
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1161
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1162
        # return
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1163
        return '/'.join(segments)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1164
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1165
    def dump (self, indent=0) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1166
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1167
            Returns a multi-line nested-node string representation of this Node
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1168
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1169
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1170
        return '\n'.join([
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1171
            "%-45s%s" % (
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1172
                ' '*indent + str(self.label) + ('/' if self.children else ''), 
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1173
                (' -> %r' % self.url) if self.url else ''
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1174
            )
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1175
        ] + [
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1176
            child.dump(indent + 4) for child in self.children
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1177
        ])
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1178
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1179
    def __str__ (self) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1180
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1181
            Return a short representation of this Node's match sequence, and our children.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1182
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1183
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1184
        # XXX: recurse for unit-test purposes...
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1185
        return "%s/[%s]" % (self.label, ','.join(str(child) for child in self.children))
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1186
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1187
class URLTree (object) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1188
    """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1189
        Map incoming URLs to URLRules and handlers, using a defined tree of URLNodes.
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1190
    """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1191
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1192
    def __init__ (self, url_rules) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1193
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1194
            Initialize the tree using the given sequence of URLRules
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1195
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1196
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1197
        # root node, matching '/'
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1198
        self.root = URLNode(None, EmptyLabel())
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1199
        
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1200
        # insert each URL into the tree
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1201
        for url in url_rules :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1202
            self.add_url(url)
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1203
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1204
    def add_url (self, url_rule) :
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1205
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1206
            Adds the given URLRule to the tree. The URLRule must begin with a root slash.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1207
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1208
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1209
        # get url's Label path
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1210
        path = url_rule.get_label_path()
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1211
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1212
        # insert into tree by path
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1213
        self.root.add_url(url_rule, path)
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1214
        
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1215
    def match (self, url) :
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1216
        """
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1217
            Find the URL object corresponding to the given incoming url, matching any ValueLabels.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1218
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1219
            Returns an (URLRule, [(value, label, is_default)]) tuple.
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1220
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1221
            XXX: handle unicode on URLs?
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1222
        """
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1223
        
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1224
        # remove leading root, since that's where we always start
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1225
        url = url.lstrip('/')
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1226
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1227
        # split it into segments
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1228
        segments = url.split('/')
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1229
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1230
        # recurse into the tree
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1231
        return self.root.match(segments)
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1232
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1233
    def evaluate (self, url, qargs=None) :
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1234
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1235
            Look up the URLRule's handler for the given incoming url:
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1236
                url         - the text-form URL
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1237
                qargs       - a [ (key, [ value ] ) ] list of query string arguments
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1238
                    
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1239
            and return:
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1240
                * the `handler` configured for the URLRule
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1241
                * a { key: value } dict of URL values suitable for use as **kwargs
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1242
                * a [ (key, [ value ] ) ] list of remaining query string arguments not included in the returned keyword
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1243
                  args
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1244
                
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1245
        """
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1246
        
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1247
        # lookup
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1248
        rule, url_values = self.match(url)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1249
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1250
        # evaluate
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1251
        args, qargs = rule.evaluate(url_values, qargs)
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1252
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1253
        return rule.handler, args, qargs
44
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1254
30af52a271a1 ext.urltree: initial import from qmsk.web
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
  1255
45
e3001377e9dc ext.urltree: improved docs and refactoring
Tero Marttila <terom@fixme.fi>
parents: 44
diff changeset
  1256