Mercurial > genshi > mirror
comparison examples/trac/trac/web/href.py @ 39:93b4dcbafd7b trunk
Copy Trac to main branch.
author | cmlenz |
---|---|
date | Mon, 03 Jul 2006 18:53:27 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
38:ee669cb9cccc | 39:93b4dcbafd7b |
---|---|
1 # -*- coding: utf-8 -*- | |
2 # | |
3 # Copyright (C) 2003-2005 Edgewall Software | |
4 # Copyright (C) 2003-2004 Jonas Borgström <jonas@edgewall.com> | |
5 # Copyright (C) 2005 Christopher Lenz <cmlenz@gmx.de> | |
6 # All rights reserved. | |
7 # | |
8 # This software is licensed as described in the file COPYING, which | |
9 # you should have received as part of this distribution. The terms | |
10 # are also available at http://trac.edgewall.com/license.html. | |
11 # | |
12 # This software consists of voluntary contributions made by many | |
13 # individuals. For the exact contribution history, see the revision | |
14 # history and logs, available at http://projects.edgewall.com/trac/. | |
15 # | |
16 # Author: Jonas Borgström <jonas@edgewall.com> | |
17 # Christopher Lenz <cmlenz@gmx.de> | |
18 | |
19 from urllib import quote, urlencode | |
20 from trac.util.text import unicode_quote, unicode_urlencode | |
21 | |
22 | |
23 class Href(object): | |
24 """ | |
25 Implements a callable that constructs URLs with the given base. The | |
26 function can be called with any number of positional and keyword | |
27 arguments which than are used to assemble the URL. | |
28 | |
29 Positional arguments are appended as individual segments to | |
30 the path of the URL: | |
31 | |
32 >>> href = Href('/trac') | |
33 >>> href('ticket', 540) | |
34 '/trac/ticket/540' | |
35 >>> href('ticket', 540, 'attachment', 'bugfix.patch') | |
36 '/trac/ticket/540/attachment/bugfix.patch' | |
37 >>> href('ticket', '540/attachment/bugfix.patch') | |
38 '/trac/ticket/540/attachment/bugfix.patch' | |
39 | |
40 If a positional parameter evaluates to None, it will be skipped: | |
41 | |
42 >>> href('ticket', 540, 'attachment', None) | |
43 '/trac/ticket/540/attachment' | |
44 | |
45 The first path segment can also be specified by calling an attribute | |
46 of the instance, as follows: | |
47 | |
48 >>> href.ticket(540) | |
49 '/trac/ticket/540' | |
50 >>> href.changeset(42, format='diff') | |
51 '/trac/changeset/42?format=diff' | |
52 | |
53 Simply calling the Href object with no arguments will return the base URL: | |
54 | |
55 >>> href() | |
56 '/trac' | |
57 | |
58 Keyword arguments are added to the query string, unless the value is None: | |
59 | |
60 >>> href = Href('/trac') | |
61 >>> href('timeline', format='rss') | |
62 '/trac/timeline?format=rss' | |
63 >>> href('timeline', format=None) | |
64 '/trac/timeline' | |
65 >>> href('search', q='foo bar') | |
66 '/trac/search?q=foo+bar' | |
67 | |
68 Multiple values for one parameter are specified using a sequence (a list or | |
69 tuple) for the parameter: | |
70 | |
71 >>> href('timeline', show=['ticket', 'wiki', 'changeset']) | |
72 '/trac/timeline?show=ticket&show=wiki&show=changeset' | |
73 | |
74 Alternatively, query string parameters can be added by passing a dict or | |
75 list as last positional argument: | |
76 | |
77 >>> href('timeline', {'from': '02/24/05', 'daysback': 30}) | |
78 '/trac/timeline?daysback=30&from=02%2F24%2F05' | |
79 | |
80 If the order of query string parameters should be preserved, you may also | |
81 pass a sequence of (name, value) tuples as last positional argument: | |
82 | |
83 >>> href('query', (('group', 'component'), ('groupdesc', 1))) | |
84 '/trac/query?group=component&groupdesc=1' | |
85 | |
86 >>> params = [] | |
87 >>> params.append(('group', 'component')) | |
88 >>> params.append(('groupdesc', 1)) | |
89 >>> href('query', params) | |
90 '/trac/query?group=component&groupdesc=1' | |
91 | |
92 By specifying an absolute base, the function returned will also generate | |
93 absolute URLs: | |
94 | |
95 >>> href = Href('http://projects.edgewall.com/trac') | |
96 >>> href('ticket', 540) | |
97 'http://projects.edgewall.com/trac/ticket/540' | |
98 | |
99 >>> href = Href('https://projects.edgewall.com/trac') | |
100 >>> href('ticket', 540) | |
101 'https://projects.edgewall.com/trac/ticket/540' | |
102 | |
103 In common usage, it may improve readability to use the function-calling | |
104 ability for the first component of the URL as mentioned earlier: | |
105 | |
106 >>> href = Href('/trac') | |
107 >>> href.ticket(540) | |
108 '/trac/ticket/540' | |
109 >>> href.browser('/trunk/README.txt', format='txt') | |
110 '/trac/browser/trunk/README.txt?format=txt' | |
111 """ | |
112 | |
113 def __init__(self, base): | |
114 self.base = base | |
115 self._derived = {} | |
116 | |
117 def __call__(self, *args, **kw): | |
118 href = self.base | |
119 if href and href[-1] == '/': | |
120 href = href[:-1] | |
121 params = [] | |
122 | |
123 def add_param(name, value): | |
124 if type(value) in (list, tuple): | |
125 for i in [i for i in value if i != None]: | |
126 params.append((name, i)) | |
127 elif v != None: | |
128 params.append((name, value)) | |
129 | |
130 if args: | |
131 lastp = args[-1] | |
132 if lastp and type(lastp) is dict: | |
133 for k,v in lastp.items(): | |
134 add_param(k, v) | |
135 args = args[:-1] | |
136 elif lastp and type(lastp) in (list, tuple): | |
137 for k,v in lastp: | |
138 add_param(k, v) | |
139 args = args[:-1] | |
140 | |
141 # build the path | |
142 path = '/'.join([unicode_quote(unicode(arg).strip('/')) for arg in args | |
143 if arg != None]) | |
144 if path: | |
145 href += '/' + path | |
146 | |
147 # assemble the query string | |
148 for k,v in kw.items(): | |
149 add_param(k, v) | |
150 | |
151 if params: | |
152 href += '?' + unicode_urlencode(params) | |
153 | |
154 return href | |
155 | |
156 def __getattr__(self, name): | |
157 if not self._derived.has_key(name): | |
158 self._derived[name] = lambda *args, **kw: self(name, *args, **kw) | |
159 return self._derived[name] | |
160 | |
161 | |
162 if __name__ == '__main__': | |
163 import doctest, sys | |
164 doctest.testmod(sys.modules[__name__]) |