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