Package qm :: Package external :: Package DocumentTemplate :: Module DT_InSV
[hide private]
[frames] | no frames]

Source Code for Module qm.external.DocumentTemplate.DT_InSV

  1  ############################################################################## 
  2  #  
  3  # Zope Public License (ZPL) Version 1.0 
  4  # ------------------------------------- 
  5  #  
  6  # Copyright (c) Digital Creations.  All rights reserved. 
  7  #  
  8  # This license has been certified as Open Source(tm). 
  9  #  
 10  # Redistribution and use in source and binary forms, with or without 
 11  # modification, are permitted provided that the following conditions are 
 12  # met: 
 13  #  
 14  # 1. Redistributions in source code must retain the above copyright 
 15  #    notice, this list of conditions, and the following disclaimer. 
 16  #  
 17  # 2. Redistributions in binary form must reproduce the above copyright 
 18  #    notice, this list of conditions, and the following disclaimer in 
 19  #    the documentation and/or other materials provided with the 
 20  #    distribution. 
 21  #  
 22  # 3. Digital Creations requests that attribution be given to Zope 
 23  #    in any manner possible. Zope includes a "Powered by Zope" 
 24  #    button that is installed by default. While it is not a license 
 25  #    violation to remove this button, it is requested that the 
 26  #    attribution remain. A significant investment has been put 
 27  #    into Zope, and this effort will continue if the Zope community 
 28  #    continues to grow. This is one way to assure that growth. 
 29  #  
 30  # 4. All advertising materials and documentation mentioning 
 31  #    features derived from or use of this software must display 
 32  #    the following acknowledgement: 
 33  #  
 34  #      "This product includes software developed by Digital Creations 
 35  #      for use in the Z Object Publishing Environment 
 36  #      (http://www.zope.org/)." 
 37  #  
 38  #    In the event that the product being advertised includes an 
 39  #    intact Zope distribution (with copyright and license included) 
 40  #    then this clause is waived. 
 41  #  
 42  # 5. Names associated with Zope or Digital Creations must not be used to 
 43  #    endorse or promote products derived from this software without 
 44  #    prior written permission from Digital Creations. 
 45  #  
 46  # 6. Modified redistributions of any form whatsoever must retain 
 47  #    the following acknowledgment: 
 48  #  
 49  #      "This product includes software developed by Digital Creations 
 50  #      for use in the Z Object Publishing Environment 
 51  #      (http://www.zope.org/)." 
 52  #  
 53  #    Intact (re-)distributions of any official Zope release do not 
 54  #    require an external acknowledgement. 
 55  #  
 56  # 7. Modifications are encouraged but must be packaged separately as 
 57  #    patches to official Zope releases.  Distributions that do not 
 58  #    clearly separate the patches from the original work must be clearly 
 59  #    labeled as unofficial distributions.  Modifications which do not 
 60  #    carry the name Zope may be packaged in any form, as long as they 
 61  #    conform to all of the clauses above. 
 62  #  
 63  #  
 64  # Disclaimer 
 65  #  
 66  #   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY 
 67  #   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 68  #   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 69  #   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS 
 70  #   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 71  #   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 72  #   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 
 73  #   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
 74  #   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
 75  #   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
 76  #   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
 77  #   SUCH DAMAGE. 
 78  #  
 79  #  
 80  # This software consists of contributions made by Digital Creations and 
 81  # many individuals on behalf of Digital Creations.  Specific 
 82  # attributions are listed in the accompanying credits file. 
 83  #  
 84  ############################################################################## 
 85  __doc__='''Sequence variables support 
 86   
 87   
 88  $Id: DT_InSV.py 694 2003-04-16 02:53:50Z sc $''' 
 89  __version__='$Revision: 694 $'[11:-2] 
 90   
 91  from string import lower, rfind, split, join 
 92  from math import sqrt 
 93  TupleType=type(()) 
 94  try: 
 95      import Missing 
 96      mv=Missing.Value 
 97  except: mv=None 
 98   
 99   
101
102 - def __init__(self,items=None,query_string='',start_name_re=None):
103 104 self.items=items 105 self.query_string=query_string 106 self.start_name_re=start_name_re 107 108 self.data=data={ 109 'previous-sequence': 0, 110 'next-sequence': 0, 111 'sequence-start': 1, 112 'sequence-end': 0, 113 }
114 115
116 - def __len__(self): return 1
117 - def number(self,index): return index+1
118 - def even(self,index): return index%2 == 0
119 - def odd(self,index): return index%2
120 - def letter(self,index): return chr(ord('a')+index)
121 - def Letter(self,index): return chr(ord('A')+index)
122 - def key(self,index): return self.items[index][0]
123 - def item(self,index, tt=type(())):
124 i=self.items[index] 125 if type(i) is tt and len(i)==2: return i[1] 126 return i
127
128 - def roman(self,index): return lower(self.Roman(index))
129
130 - def Roman(self,num):
131 # Force number to be an integer value 132 num = int(num)+1 133 134 # Initialize roman as an empty string 135 roman = '' 136 137 while num >= 1000: 138 num = num - 1000 139 roman = '%sM' % roman 140 141 while num >= 500: 142 num = num - 500 143 roman = '%sD' % roman 144 145 while num >= 100: 146 num = num - 100 147 roman = '%sC' % roman 148 149 while num >= 50: 150 num = num - 50 151 roman = '%sL' % roman 152 153 while num >= 10: 154 num = num - 10 155 roman = '%sX' % roman 156 157 while num >= 5: 158 num = num - 5 159 roman = '%sV' % roman 160 161 while num < 5 and num >= 1: 162 num = num - 1 163 roman = '%sI' % roman 164 165 # Replaces special cases in Roman Numerals 166 167 roman = sub('DCCCC', 'CM', roman) 168 roman = sub('CCCC', 'CD', roman) 169 roman = sub('LXXXX', 'XC', roman) 170 roman = sub('XXXX', 'XL', roman) 171 roman = sub('VIIII', 'IX', roman) 172 roman = sub('IIII', 'IV', roman) 173 174 return roman
175 176
177 - def value(self,index,name):
178 data=self.data 179 item=self.items[index] 180 if type(item)==TupleType and len(item)==2: 181 item=item[1] 182 if data['mapping']: return item[name] 183 return getattr(item,name)
184
185 - def first(self,name,key=''):
186 data=self.data 187 if data['sequence-start']: return 1 188 index=data['sequence-index'] 189 return self.value(index,name) != self.value(index-1,name)
190
191 - def last(self,name,key=''):
192 data=self.data 193 if data['sequence-end']: return 1 194 index=data['sequence-index'] 195 return self.value(index,name) != self.value(index+1,name)
196
197 - def length(self, ignored):
198 l=self.data['sequence-length']=len(self.items) 199 return l
200
201 - def query(self, *ignored):
202 if self.start_name_re is None: raise KeyError, 'sequence-query' 203 query_string=self.query_string 204 while query_string and query_string[:1] in '?&': 205 query_string=query_string[1:] 206 while query_string[-1:] == '&': 207 query_string=query_string[:-1] 208 if query_string: 209 query_string='&%s&' % query_string 210 re=self.start_name_re 211 l=re.search_group(query_string, (0,)) 212 if l: 213 v=l[1] 214 l=l[0] 215 query_string=(query_string[:l]+ 216 query_string[l+len(v)-1:]) 217 query_string='?'+query_string[1:] 218 else: query_string='?' 219 self.data['sequence-query']=query_string 220 return query_string
221 222 223 statistic_names=( 224 'total', 'count', 'min', 'max', 'median', 'mean', 225 'variance', 'variance-n','standard-deviation', 'standard-deviation-n', 226 ) 227
228 - def statistics(self,name,key):
229 items=self.items 230 data=self.data 231 mapping=data['mapping'] 232 count=sum=sumsq=0 233 min=max=None 234 scount=smin=smax=None 235 values=[] 236 svalues=[] 237 for item in items: 238 try: 239 if mapping: item=item[name] 240 else: item=getattr(item,name) 241 try: 242 if item is mv: 243 item = None 244 if type(item)==type(1): 245 s=item*long(item) 246 else: 247 s=item*item 248 sum=sum+item 249 sumsq=sumsq+s 250 values.append(item) 251 if min is None: 252 min=max=item 253 else: 254 if item < min: min=item 255 if item > max: max=item 256 except: 257 if item is not None and item is not mv: 258 if smin is None: smin=smax=item 259 else: 260 if item < smin: smin=item 261 if item > smax: smax=item 262 svalues.append(item) 263 except: pass 264 265 # Initialize all stats to empty strings: 266 for stat in self.statistic_names: data['%s-%s' % (stat,name)]='' 267 268 count=len(values) 269 try: # Numeric statistics 270 n=float(count) 271 mean=sum/n 272 sumsq=sumsq/n - mean*mean 273 data['mean-%s' % name]=mean 274 data['total-%s' % name]=sum 275 data['variance-n-%s' % name]=sumsq 276 data['standard-deviation-n-%s' % name]=sqrt(sumsq) 277 if count > 1: 278 sumsq=sumsq*n/(n-1) 279 data['variance-%s' % name]=sumsq 280 data['standard-deviation-%s' % name]=sqrt(sumsq) 281 else: 282 data['variance-%s' % name]='' 283 data['standard-deviation-%s' % name]='' 284 except: 285 if min is None: min,max,values=smin,smax,svalues 286 else: 287 if smin < min: min=smin 288 if smax > max: max=smax 289 values=values+svalues 290 count=len(values) 291 292 data['count-%s' % name]=count 293 # data['_values']=values 294 if min is not None: 295 data['min-%s' % name]=min 296 data['max-%s' % name]=max 297 values.sort() 298 if count==1: 299 data['median-%s' % name]=min 300 else: 301 n=count+1 302 if n/2*2==n: data['median-%s' % name]=values[n/2-1] 303 else: 304 n=n/2 305 try: data['median-%s' % name]=(values[n]+values[n-1])/2 306 except: 307 try: data['median-%s' % name]=( 308 "between %s and %s" % (values[n],values[n-1])) 309 except: pass 310 311 return data[key]
312
313 - def next_batches(self, suffix='batches',key=''):
314 if suffix != 'batches': raise KeyError, key 315 data=self.data 316 sequence=self.items 317 try: 318 if not data['next-sequence']: return () 319 sz=data['sequence-step-size'] 320 start=data['sequence-step-start'] 321 end=data['sequence-step-end'] 322 l=len(sequence) 323 orphan=data['sequence-step-orphan'] 324 overlap=data['sequence-step-overlap'] 325 except: AttributeError, 'next-batches' 326 r=[] 327 while end < l: 328 start,end,spam=opt(end+1-overlap,0,sz,orphan,sequence) 329 v=sequence_variables(self.items, 330 self.query_string,self.start_name_re) 331 d=v.data 332 d['batch-start-index']=start-1 333 d['batch-end-index']=end-1 334 d['batch-size']=end+1-start 335 d['mapping']=data['mapping'] 336 r.append(v) 337 data['next-batches']=r 338 return r
339
340 - def previous_batches(self, suffix='batches',key=''):
341 if suffix != 'batches': raise KeyError, key 342 data=self.data 343 sequence=self.items 344 try: 345 if not data['previous-sequence']: return () 346 sz=data['sequence-step-size'] 347 start=data['sequence-step-start'] 348 end=data['sequence-step-end'] 349 l=len(sequence) 350 orphan=data['sequence-step-orphan'] 351 overlap=data['sequence-step-overlap'] 352 except: AttributeError, 'previous-batches' 353 r=[] 354 while start > 1: 355 start,end,spam=opt(0,start-1+overlap,sz,orphan,sequence) 356 v=sequence_variables(self.items, 357 self.query_string,self.start_name_re) 358 d=v.data 359 d['batch-start-index']=start-1 360 d['batch-end-index']=end-1 361 d['batch-size']=end+1-start 362 d['mapping']=data['mapping'] 363 r.append(v) 364 r.reverse() 365 data['previous-batches']=r 366 return r
367 368 369 special_prefixes={ 370 'first': first, 371 'last': last, 372 'previous': previous_batches, 373 'next': next_batches, 374 # These two are for backward compatability with a missfeature: 375 'sequence-index': lambda self, suffix, key: self['sequence-'+suffix], 376 'sequence-index-is': lambda self, suffix, key: self['sequence-'+suffix], 377 } 378 for n in statistic_names: special_prefixes[n]=statistics 379
380 - def __getitem__(self,key, 381 special_prefixes=special_prefixes, 382 special_prefix=special_prefixes.has_key 383 ):
384 data=self.data 385 if data.has_key(key): return data[key] 386 387 l=rfind(key,'-') 388 if l < 0: raise KeyError, key 389 390 suffix=key[l+1:] 391 prefix=key[:l] 392 393 if hasattr(self, suffix): 394 try: v=data[prefix+'-index'] 395 except: pass 396 else: return getattr(self,suffix)(v) 397 398 if special_prefix(prefix): 399 return special_prefixes[prefix](self, suffix, key) 400 401 if prefix[-4:]=='-var': 402 prefix=prefix[:-4] 403 try: return self.value(data[prefix+'-index'],suffix) 404 except: pass 405 406 if key=='sequence-query': return self.query() 407 408 raise KeyError, key
409 410 411 412
413 -def sub(s1, s2, src):
414 return join(split(src, s1), s2)
415
416 -def opt(start,end,size,orphan,sequence):
417 if size < 1: 418 if start > 0 and end > 0 and end >= start: 419 size=end+1-start 420 else: size=7 421 422 if start > 0: 423 424 try: sequence[start-1] 425 except: start=len(sequence) 426 # if start > l: start=l 427 428 if end > 0: 429 if end < start: end=start 430 else: 431 end=start+size-1 432 try: sequence[end+orphan-1] 433 except: end=len(sequence) 434 # if l - end < orphan: end=l 435 elif end > 0: 436 try: sequence[end-1] 437 except: end=len(sequence) 438 # if end > l: end=l 439 start=end+1-size 440 if start - 1 < orphan: start=1 441 else: 442 start=1 443 end=start+size-1 444 try: sequence[end+orphan-1] 445 except: end=len(sequence) 446 # if l - end < orphan: end=l 447 return start,end,size
448