1
2
3
4
5
6
7
8
9
10
11
12
13 __doc__='''Variable insertion parameters
14
15 When inserting variables, parameters may be specified to
16 control how the data will be formatted. In HTML source, the
17 'fmt' parameter is used to specify a C-style or custom format
18 to be used when inserting an object. In EPFS source, the 'fmt'
19 parameter is only used for custom formats, a C-style format is
20 specified after the closing parenthesis.
21
22 Custom formats
23
24 A custom format is used when outputing user-defined
25 objects. The value of a custom format is a method name to
26 be invoked on the object being inserted. The method should
27 return an object that, when converted to a string, yields
28 the desired text. For example, the DTML code::
29
30 <dtml-var date fmt=DayOfWeek>
31
32 Inserts the result of calling the method 'DayOfWeek' of the
33 object bound to the variable 'date', with no arguments.
34
35 In addition to object methods, serveral additional custom
36 formats are available:
37
38 'whole-dollars' -- Show a numeric value with a dollar symbol.
39
40 'dollars-and-cents' -- Show a numeric value with a dollar
41 symbol and two decimal places.
42
43 'collection-length' -- Get the length of a collection of objects.
44
45 Note that when using the EPFS source format, both a
46 C-style and a custom format may be provided. In this case,
47 the C-Style format is applied to the result of calling
48 the custom formatting method.
49
50 Null values and missing variables
51
52 In some applications, and especially in database applications,
53 data variables may alternate between "good" and "null" or
54 "missing" values. A format that is used for good values may be
55 inappropriate for null values. For this reason, the 'null'
56 parameter can be used to specify text to be used for null
57 values. Null values are defined as values that:
58
59 - Cannot be formatted with the specified format, and
60
61 - Are either the special Python value 'None' or
62 are false and yield an empty string when converted to
63 a string.
64
65 For example, when showing a monitary value retrieved from a
66 database that is either a number or a missing value, the
67 following variable insertion might be used::
68
69 <dtml-var cost fmt="$%.2d" null=\'n/a\'>
70
71 Missing values are providing for variables which are not
72 present in the name space, rather than raising an NameError,
73 you could do this:
74
75 <dtml-var cost missing=0>
76
77 and in this case, if cost was missing, it would be set to 0.
78 In the case where you want to deal with both at the same time,
79 you can use 'default':
80
81 <dtml-var description default=''>
82
83 In this case, it would use '' if the value was null or if the
84 variable was missing.
85
86 String manipulation
87
88 A number of special attributes are provided to transform the
89 value after formatting has been applied. These parameters
90 are supplied without arguments.
91
92 'lower' -- cause all upper-case letters to be converted to lower case.
93
94 'upper' -- cause all upper-case letters to be converted to lower case.
95
96 'capitalize' -- cause the first character of the inserted value
97 to be converted to upper case.
98
99 'spacify' -- cause underscores in the inserted value to be
100 converted to spaces.
101
102 'thousands_commas' -- cause commas to be inserted every three
103 digits to the left of a decimal point in values containing
104 numbers. For example, the value, "12000 widgets" becomes
105 "12,000 widgets".
106
107 'html_quote' -- convert characters that have special meaning
108 in HTML to HTML character entities.
109
110 'url_quote' -- convert characters that have special meaning
111 in URLS to HTML character entities using decimal values.
112
113 'url_quote_plus' -- like url_quote but also replace blank
114 space characters with '+'. This is needed for building
115 query strings in some cases.
116
117 'sql_quote' -- Convert single quotes to pairs of single
118 quotes. This is needed to safely include values in
119 Standard Query Language (SQL) strings.
120
121 'newline_to_br' -- Convert newlines and carriage-return and
122 newline combinations to break tags.
123
124 'url' -- Get the absolute URL of the object by calling it\'s
125 'absolute_url' method, if it has one.
126
127 Truncation
128
129 The attributes 'size' and 'etc' can be used to truncate long
130 strings. If the 'size' attribute is specified, the string to
131 be inserted is truncated at the given length. If a space
132 occurs in the second half of the truncated string, then the
133 string is further truncated to the right-most space. After
134 truncation, the value given for the 'etc' attribute is added to
135 the string. If the 'etc' attribute is not provided, then '...'
136 is used. For example, if the value of spam is
137 '"blah blah blah blah"', then the tag
138 '<!--#var spam size=10-->' inserts '"blah blah ..."'.
139
140
141 Evaluating expressions without rendering results
142
143 A 'call' tag is provided for evaluating named objects or expressions
144 without rendering the result.
145
146
147 '''
148 __rcs_id__='$Id: DT_Var.py 1069 2008-11-13 21:55:43Z stefan $'
149 __version__='$Revision: 1069 $'[11:-2]
150
151 from DT_Util import parse_params, name_param, html_quote, str
152 import string, re, sys
153 from urllib import quote, quote_plus
154
156 name='var'
157 expr=None
158
160 if args[:4]=='var ': args=args[4:]
161 args = parse_params(args, name='', lower=1, upper=1, expr='',
162 capitalize=1, spacify=1, null='', fmt='s',
163 size=0, etc='...', thousands_commas=1,
164 html_quote=1, url_quote=1, sql_quote=1,
165 url_quote_plus=1, missing='',
166 newline_to_br=1, url=1)
167 self.args=args
168
169 self.modifiers=tuple(
170 map(lambda t: t[1],
171 filter(lambda m, args=args, used=args.has_key:
172 used(m[0]) and args[m[0]],
173 modifiers)))
174
175 name, expr = name_param(args,'var',1)
176
177 self.__name__, self.expr = name, expr
178 self.fmt = fmt
179
180 if len(args)==1 and fmt=='s':
181 if expr is None: expr=name
182 else: expr=expr.eval
183 self.simple_form=(expr,)
184
186 args=self.args
187 have_arg=args.has_key
188 name=self.__name__
189
190 val=self.expr
191
192 if val is None:
193 if md.has_key(name):
194 if have_arg('url'):
195 val=md.getitem(name,0)
196 val=val.absolute_url()
197 else:
198 val = md[name]
199 else:
200 if have_arg('missing'):
201 return args['missing']
202 else:
203 raise KeyError, name
204 else:
205 val=val.eval(md)
206 if have_arg('url'): val=val.absolute_url()
207
208 __traceback_info__=name, val, args
209
210 if have_arg('null') and not val and val != 0:
211
212 return args['null']
213
214
215
216 if have_arg('fmt'):
217 fmt=args['fmt']
218 if have_arg('null') and not val and val != 0:
219 try:
220 if hasattr(val, fmt):
221 val = getattr(val,fmt)()
222 elif special_formats.has_key(fmt):
223 val = special_formats[fmt](val, name, md)
224 elif fmt=='': val=''
225 else: val = fmt % val
226 except:
227 t, v= sys.exc_type, sys.exc_value
228 if hasattr(sys, 'exc_info'): t, v = sys.exc_info()[:2]
229 if val is None or not str(val): return args['null']
230 raise t, v
231
232 else:
233
234
235 if hasattr(val, fmt):
236 val = getattr(val,fmt)()
237 elif special_formats.has_key(fmt):
238 val = special_formats[fmt](val, name, md)
239 elif fmt=='': val=''
240 else: val = fmt % val
241
242
243 fmt=self.fmt
244 if fmt=='s': val=str(val)
245 else: val = ('%'+self.fmt) % (val,)
246
247
248 for f in self.modifiers: val=f(val)
249
250 if have_arg('size'):
251 size=args['size']
252 try: size=int(size)
253 except: raise 'Document Error',(
254 '''a <code>size</code> attribute was used in a <code>var</code>
255 tag with a non-integer value.''')
256 if len(val) > size:
257 val=val[:size]
258 l=val.rfind(' ')
259 if l > size/2:
260 val=val[:l+1]
261 if have_arg('etc'): l=args['etc']
262 else: l='...'
263 val=val+l
264
265 return val
266
267 __call__=render
268
279
280
281 -def url_quote(v, name='(Unknown name)', md={}):
283
285 return quote_plus(str(v))
286
288 return unquote(str(v))
289
291 return unquote_plus(str(v))
292
294 v=str(v)
295 if v.find('\r') >= 0: v=''.join(v.split('\r'))
296 if v.find('\n') >= 0: v='<br />\n'.join(v.split('\n'))
297 return v
298
300 try: return "$%d" % v
301 except: return ''
302
304 try: return "$%.2f" % v
305 except: return ''
306
310 v=str(v)
311 vl=v.split('.')
312 if not vl: return v
313 v=vl[0]
314 del vl[0]
315 if vl: s='.'+'.'.join(vl)
316 else: s=''
317 mo=thou(v)
318 while mo is not None:
319 l = mo.start(0)
320 v=v[:l+1]+','+v[l+1:]
321 mo=thou(v)
322 return v+s
323
328
333
336
337 -def len_comma(v, name='(Unknown name)', md={}):
339
340 StructuredText=None
341 -def structured_text(v, name='(Unknown name)', md={}):
342 global StructuredText
343 if StructuredText is None: import StructuredText
344 return str(StructuredText.html_with_references(str(v), 3))
345
346 -def sql_quote(v, name='(Unknown name)', md={}):
347 """Quote single quotes in a string by doubling them.
348
349 This is needed to securely insert values into sql
350 string literals in templates that generate sql.
351 """
352 if v.find("'") >= 0: return v.replace("'", "''")
353 return v
354
355 special_formats={
356 'whole-dollars': whole_dollars,
357 'dollars-and-cents': dollars_and_cents,
358 'collection-length': len_format,
359 'structured-text': structured_text,
360
361
362 'sql-quote': sql_quote,
363 'html-quote': html_quote,
364 'url-quote': url_quote,
365 'url-quote-plus': url_quote_plus,
366 'url-unquote': url_unquote,
367 'url-unquote-plus': url_unquote_plus,
368 'multi-line': newline_to_br,
369 'comma-numeric': thousands_commas,
370 'dollars-with-commas': whole_dollars_with_commas,
371 'dollars-and-cents-with-commas': dollars_and_cents_with_commas,
372 }
373
375 if val.find('_') >= 0: val=val.replace('_', ' ')
376 return val
377
378 modifiers=(html_quote, url_quote, url_quote_plus, url_unquote,
379 url_unquote_plus, newline_to_br,
380 string.lower, string.upper, string.capitalize, spacify,
381 thousands_commas, sql_quote, url_unquote, url_unquote_plus)
382 modifiers=map(lambda f: (f.__name__, f), modifiers)
383
407