]> git.pld-linux.org Git - packages/QMTest.git/blob - QMTest-python25.patch
BR: rpmbuild(macros) >= 1.710
[packages/QMTest.git] / QMTest-python25.patch
1 CodeSourcery > List Archives > qmtest  
2 Actions  
3 Post 
4 Subscribe 
5 Unsubscribe 
6 [Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] 
7
8 [qmtest] patch: Upgrade DocumentTemplate package for python 2.5 compatibility. 
9
10 To: qmtest@xxxxxxxxxxxxxxxx 
11
12 Subject: [qmtest] patch: Upgrade DocumentTemplate package for python 2.5 
13 compatibility. 
14
15 From: Stefan Seefeld <stefan@xxxxxxxxxxxxxxxx> 
16
17 Date: Fri, 09 Feb 2007 19:47:06 -0500 
18
19 The attached patch attempts to partially replace the (very old) version of
20 the DocumentTemplate package once imported from Zope by a never version,
21 in an attempt to make QMTest compatible with python 2.5.
22
23 This version mainly replaces all uses of the 'regex' module by 're' (which,
24 unfortunately is not trivial due to some subtle differences between the two,
25 but it also contains some other small changes (e.g. replaces deprecated
26 calls such as atoi() by int()).
27
28 When using python 2.5, a warning about the (now deprecated) 'with' token
29 is issued (as that apparently will become a keyword in 2.6), so I'm looking
30 into replacing that, or merging more changes from a current Zope version
31 in, depending on which is easier.
32
33 Thanks,
34                 Stefan
35
36 -- 
37 Stefan Seefeld
38 CodeSourcery
39 stefan@xxxxxxxxxxxxxxxx
40 (650) 331-3385 x718
41
42 Modified for QMTest-2.3 by <japhy@pld-linux.org>
43 diff -ur qm-2.3.vanilla/qm/external/DocumentTemplate/DT_HTML.py qm-2.3/qm/external/DocumentTemplate/DT_HTML.py
44 --- qm-2.3.vanilla/qm/external/DocumentTemplate/DT_HTML.py      2005-02-11 17:11:16.000000000 +0100
45 +++ qm-2.3/qm/external/DocumentTemplate/DT_HTML.py      2007-07-23 22:13:09.000000000 +0200
46 @@ -1,130 +1,55 @@
47  ##############################################################################
48 -# 
49 -# Zope Public License (ZPL) Version 1.0
50 -# -------------------------------------
51 -# 
52 -# Copyright (c) Digital Creations.  All rights reserved.
53 -# 
54 -# This license has been certified as Open Source(tm).
55 -# 
56 -# Redistribution and use in source and binary forms, with or without
57 -# modification, are permitted provided that the following conditions are
58 -# met:
59 -# 
60 -# 1. Redistributions in source code must retain the above copyright
61 -#    notice, this list of conditions, and the following disclaimer.
62 -# 
63 -# 2. Redistributions in binary form must reproduce the above copyright
64 -#    notice, this list of conditions, and the following disclaimer in
65 -#    the documentation and/or other materials provided with the
66 -#    distribution.
67 -# 
68 -# 3. Digital Creations requests that attribution be given to Zope
69 -#    in any manner possible. Zope includes a "Powered by Zope"
70 -#    button that is installed by default. While it is not a license
71 -#    violation to remove this button, it is requested that the
72 -#    attribution remain. A significant investment has been put
73 -#    into Zope, and this effort will continue if the Zope community
74 -#    continues to grow. This is one way to assure that growth.
75 -# 
76 -# 4. All advertising materials and documentation mentioning
77 -#    features derived from or use of this software must display
78 -#    the following acknowledgement:
79 -# 
80 -#      "This product includes software developed by Digital Creations
81 -#      for use in the Z Object Publishing Environment
82 -#      (http://www.zope.org/)."
83 -# 
84 -#    In the event that the product being advertised includes an
85 -#    intact Zope distribution (with copyright and license included)
86 -#    then this clause is waived.
87 -# 
88 -# 5. Names associated with Zope or Digital Creations must not be used to
89 -#    endorse or promote products derived from this software without
90 -#    prior written permission from Digital Creations.
91 -# 
92 -# 6. Modified redistributions of any form whatsoever must retain
93 -#    the following acknowledgment:
94 -# 
95 -#      "This product includes software developed by Digital Creations
96 -#      for use in the Z Object Publishing Environment
97 -#      (http://www.zope.org/)."
98 -# 
99 -#    Intact (re-)distributions of any official Zope release do not
100 -#    require an external acknowledgement.
101 -# 
102 -# 7. Modifications are encouraged but must be packaged separately as
103 -#    patches to official Zope releases.  Distributions that do not
104 -#    clearly separate the patches from the original work must be clearly
105 -#    labeled as unofficial distributions.  Modifications which do not
106 -#    carry the name Zope may be packaged in any form, as long as they
107 -#    conform to all of the clauses above.
108 -# 
109 -# 
110 -# Disclaimer
111 -# 
112 -#   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
113 -#   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
114 -#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
115 -#   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
116 -#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
117 -#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
118 -#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
119 -#   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
120 -#   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
121 -#   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
122 -#   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
123 -#   SUCH DAMAGE.
124 -# 
125 -# 
126 -# This software consists of contributions made by Digital Creations and
127 -# many individuals on behalf of Digital Creations.  Specific
128 -# attributions are listed in the accompanying credits file.
129 -# 
130 +#
131 +# Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
132 +#
133 +# This software is subject to the provisions of the Zope Public License,
134 +# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
135 +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
136 +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
137 +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
138 +# FOR A PARTICULAR PURPOSE
139 +#
140  ##############################################################################
141  """HTML formated DocumentTemplates
142  
143  $Id$"""
144  
145  from DT_String import String, FileMixin
146 -import DT_String, regex
147 +import DT_String, re
148  from DT_Util import ParseError, str
149 -from string import strip, find, split, join, rfind, replace
150  
151  class dtml_re_class:
152 -
153 +    """ This needs to be replaced before 2.4.  It's a hackaround. """
154      def search(self, text, start=0,
155 -               name_match=regex.compile('[\0- ]*[a-zA-Z]+[\0- ]*').match,
156 -               end_match=regex.compile('[\0- ]*\(/\|end\)',
157 -                                       regex.casefold).match,
158 -               start_search=regex.compile('[<&]').search,
159 -               ent_name=regex.compile('[-a-zA-Z0-9_.]+').match,
160 -               find=find,
161 -               strip=strip,
162 -               replace=replace,
163 +               name_match=re.compile('[\000- ]*[a-zA-Z]+[\000- ]*').match,
164 +               end_match=re.compile('[\000- ]*(/|end)', re.I).match,
165 +               start_search=re.compile('[<&]').search,
166 +               ent_name=re.compile('[-a-zA-Z0-9_.]+').match,
167                 ):
168  
169          while 1:
170 -            s=start_search(text, start)
171 -            if s < 0: return -1
172 +            mo = start_search(text, start)
173 +            if mo is None: return None
174 +            s = mo.start(0)
175              if text[s:s+5] == '<!--#':
176                  n=s+5
177 -                e=find(text,'-->',n)
178 -                if e < 0: return -1
179 +                e=text.find('-->',n)
180 +                if e < 0: return None
181                  en=3
182  
183 -                l=end_match(text,n)
184 -                if l > 0:
185 -                    end=strip(text[n:n+l])
186 +                mo =end_match(text,n)
187 +                if mo is not None:
188 +                    l = mo.end(0) - mo.start(0)
189 +                    end=text[n:n+l].strip()
190                      n=n+l
191                  else: end=''
192  
193              elif text[s:s+6] == '<dtml-':
194                  e=n=s+6
195                  while 1:
196 -                    e=find(text,'>',e+1)
197 -                    if e < 0: return -1
198 -                    if len(split(text[n:e],'"'))%2:
199 +                    e=text.find('>',e+1)
200 +                    if e < 0: return None
201 +                    if len(text[n:e].split('"'))%2:
202                          # check for even number of "s inside
203                          break
204  
205 @@ -134,9 +60,9 @@
206              elif text[s:s+7] == '</dtml-':
207                  e=n=s+7
208                  while 1:
209 -                    e=find(text,'>',e+1)
210 -                    if e < 0: return -1
211 -                    if len(split(text[n:e],'"'))%2:
212 +                    e=text.find('>',e+1)
213 +                    if e < 0: return None
214 +                    if len(text[n:e].split('"'))%2:
215                          # check for even number of "s inside
216                          break
217  
218 @@ -146,48 +72,54 @@
219              else:
220                  if text[s:s+5] == '&dtml' and text[s+5] in '.-':
221                      n=s+6
222 -                    e=find(text,';',n)                        
223 +                    e=text.find(';',n)
224                      if e >= 0:
225                          args=text[n:e]
226                          l=len(args)
227 -                        if ent_name(args) == l:
228 -                            d=self.__dict__
229 -                            if text[s+5]=='-':
230 -                                d[1]=d['end']=''
231 -                                d[2]=d['name']='var'
232 -                                d[0]=text[s:e+1]
233 -                                d[3]=d['args']=args+' html_quote'
234 -                                return s
235 -                            else:
236 -                                nn=find(args,'-')
237 -                                if nn >= 0 and nn < l-1:
238 +                        mo = ent_name(args)
239 +                        if mo is not None:
240 +                            if mo.end(0)-mo.start(0) == l:
241 +                                d=self.__dict__
242 +                                if text[s+5]=='-':
243                                      d[1]=d['end']=''
244                                      d[2]=d['name']='var'
245                                      d[0]=text[s:e+1]
246 -                                    args=(args[nn+1:]+' '+
247 -                                          replace(args[:nn],'.',' '))
248 -                                    d[3]=d['args']=args
249 -                                    return s
250 -                        
251 +                                    d[3]=d['args']=args+' html_quote'
252 +                                    self._start = s
253 +                                    return self
254 +                                else:
255 +                                    nn=args.find('-')
256 +                                    if nn >= 0 and nn < l-1:
257 +                                        d[1]=d['end']=''
258 +                                        d[2]=d['name']='var'
259 +                                        d[0]=text[s:e+1]
260 +                                        args=args[nn+1:]+' '+ \
261 +                                              args[:nn].replace('.',' ')
262 +                                        d[3]=d['args']=args
263 +                                        self._start = s
264 +                                        return self
265 +
266                  start=s+1
267                  continue
268  
269              break
270  
271 -        l=name_match(text,n)
272 -        if l < 0: return l
273 +        mo = name_match(text,n)
274 +        if mo is None: return None
275 +        l = mo.end(0) - mo.start(0)
276 +
277          a=n+l
278 -        name=strip(text[n:a])
279 +        name=text[n:a].strip()
280  
281 -        args=strip(text[a:e])
282 +        args=text[a:e].strip()
283  
284          d=self.__dict__
285          d[0]=text[s:e+en]
286          d[1]=d['end']=end
287          d[2]=d['name']=name
288          d[3]=d['args']=args
289 -
290 -        return s
291 +        self._start = s
292 +        return self
293  
294      def group(self, *args):
295          get=self.__dict__.get
296 @@ -195,7 +127,8 @@
297              return get(args[0])
298          return tuple(map(get, args))
299  
300 -        
301 +    def start(self, *args):
302 +        return self._start
303  
304  class HTML(DT_String.String):
305      """HTML Document Templates
306 @@ -217,7 +150,7 @@
307          return dtml_re_class()
308  
309      parseTag__roles__=()
310 -    def parseTag(self, tagre, command=None, sargs=''):
311 +    def parseTag(self, match_ob, command=None, sargs=''):
312          """Parse a tag using an already matched re
313  
314          Return: tag, args, command, coname
315 @@ -229,8 +162,8 @@
316                 coname is the name of a continue tag (e.g. else)
317                   or None otherwise
318          """
319 -        tag, end, name, args, =tagre.group(0, 'end', 'name', 'args')
320 -        args=strip(args)
321 +        tag, end, name, args = match_ob.group(0, 'end', 'name', 'args')
322 +        args=args.strip()
323          if end:
324              if not command or name != command.name:
325                  raise ParseError, ('unexpected end tag', tag)
326 @@ -245,7 +178,7 @@
327                  if not (args==sargs or
328                          args==sargs[:l] and sargs[l:l+1] in ' \t\n'):
329                      return tag, args, self.commands[name], None
330 -            
331 +
332              return tag, args, None, name
333  
334          try: return tag, args, self.commands[name], None
335 @@ -256,7 +189,7 @@
336      def SubTemplate(self, name): return HTML('', __name__=name)
337  
338      varExtra__roles__=()
339 -    def varExtra(self,tagre): return 's'
340 +    def varExtra(self, match_ob): return 's'
341  
342      manage_edit__roles__=()
343      def manage_edit(self,data,REQUEST=None):
344 @@ -274,7 +207,7 @@
345                         (('"'), '&quot;'))): #"
346          if text is None: text=self.read_raw()
347          for re,name in character_entities:
348 -            if find(text, re) >= 0: text=join(split(text,re),name)
349 +            if text.find(re) >= 0: text=name.join(text.split(re))
350          return text
351  
352      errQuote__roles__=()
353 @@ -293,7 +226,7 @@
354      manage_editForm__roles__=()
355      def manage_editForm(self, URL1, REQUEST):
356          '''Display doc template editing form''' #"
357 -        
358 +
359          return self._manage_editForm(
360              self,
361              mapping=REQUEST,
362 @@ -319,7 +252,7 @@
363      def manage_edit(self,data,PARENTS,URL1,REQUEST):
364          'edit a template'
365          newHTML=self.copy_class(data,self.globals,self.__name__)
366 -        setattr(PARENTS[1],URL1[rfind(URL1,'/')+1:],newHTML)
367 +        setattr(PARENTS[1],URL1[URL1.rfind('/')+1:],newHTML)
368          return self.editConfirmation(self,REQUEST)
369  
370  
371 @@ -367,10 +300,10 @@
372                      PARENTS=[],URL1='',URL2='',REQUEST='', SUBMIT=''):
373          'edit a template'
374          if SUBMIT==FactoryDefaultString: return self.manage_default(REQUEST)
375 -        if find(data,'\r'):
376 -            data=join(split(data,'\r\n'),'\n\r')
377 -            data=join(split(data,'\n\r'),'\n')
378 -            
379 +        if data.find('\r'):
380 +            data='\n\r'.join(data.split('\r\n'))
381 +            data='\n'.join(data.split('\n\r'))
382 +
383          if self.edited_source:
384              self.edited_source=data
385              self._v_cooked=self.cook()
386 @@ -379,5 +312,5 @@
387              newHTML=self.__class__()
388              newHTML.__setstate__(self.__getstate__())
389              newHTML.edited_source=data
390 -            setattr(PARENTS[1],URL1[rfind(URL1,'/')+1:],newHTML)
391 +            setattr(PARENTS[1],URL1[URL1.rfind('/')+1:],newHTML)
392          if REQUEST: return self.editConfirmation(self,REQUEST)
393 diff -ur qm-2.3.vanilla/qm/external/DocumentTemplate/DT_In.py qm-2.3/qm/external/DocumentTemplate/DT_In.py
394 --- qm-2.3.vanilla/qm/external/DocumentTemplate/DT_In.py        2005-02-11 17:11:16.000000000 +0100
395 +++ qm-2.3/qm/external/DocumentTemplate/DT_In.py        2007-07-23 22:13:09.000000000 +0200
396 @@ -387,8 +387,7 @@
397  
398  from DT_Util import ParseError, parse_params, name_param, str
399  from DT_Util import render_blocks, InstanceDict, ValidationError, VSEval, expr_globals
400 -from string import find, atoi, join, split
401 -import ts_regex
402 +import re
403  from DT_InSV import sequence_variables, opt
404  TupleType=type(())
405  
406 @@ -449,11 +448,11 @@
407          if has_key('start'):
408              v=args['start']
409              if type(v)==type(''):
410 -                try: atoi(v)
411 +                try: int(v)
412                  except:
413 -                    self.start_name_re=ts_regex.compile(
414 +                    self.start_name_re=re.compile(
415                          '&+'+
416 -                        join(map(lambda c: "[%s]" % c, v),'')+
417 +                        ''.join(["[%s]" % c for c in v])+
418                          '=[0-9]+&+')
419                      
420          name,expr=name_param(args,'in',1)
421 @@ -628,7 +627,7 @@
422                      if index==first: kw['sequence-start']=0
423  
424  
425 -                result=join(result, '')
426 +                result=''.join(result)
427  
428          finally:
429              if cache: pop()
430 @@ -712,7 +711,7 @@
431                      finally: pop()
432                      if index==0: kw['sequence-start']=0
433  
434 -                result=join(result, '')
435 +                result=''.join(result)
436  
437          finally:
438              if cache: pop()
439 @@ -727,7 +726,7 @@
440          # eg <dtml in "foo" sort=akey,anotherkey>
441          
442          sort=self.sort
443 -        sortfields = split(sort,',')   # multi sort = key1,key2 
444 +        sortfields = sort.split(',')   # multi sort = key1,key2 
445          multsort = len(sortfields) > 1 # flag: is multiple sort
446          mapping=self.mapping
447          isort=not sort
448 @@ -784,8 +783,8 @@
449      try: v=params[name]
450      except: v=default
451      if v:
452 -        try: v=atoi(v)
453 +        try: v=int(v)
454          except:
455              v=md[v]
456 -            if type(v) is st: v=atoi(v)
457 +            if type(v) is st: v=int(v)
458      return v
459 diff -ur qm-2.3.vanilla/qm/external/DocumentTemplate/DT_Let.py qm-2.3/qm/external/DocumentTemplate/DT_Let.py
460 --- qm-2.3.vanilla/qm/external/DocumentTemplate/DT_Let.py       2005-02-11 17:11:16.000000000 +0100
461 +++ qm-2.3/qm/external/DocumentTemplate/DT_Let.py       2007-07-23 22:13:38.000000000 +0200
462 @@ -1,92 +1,20 @@
463  ##############################################################################
464 -# 
465 -# Zope Public License (ZPL) Version 1.0
466 -# -------------------------------------
467 -# 
468 -# Copyright (c) Digital Creations.  All rights reserved.
469 -# 
470 -# This license has been certified as Open Source(tm).
471 -# 
472 -# Redistribution and use in source and binary forms, with or without
473 -# modification, are permitted provided that the following conditions are
474 -# met:
475 -# 
476 -# 1. Redistributions in source code must retain the above copyright
477 -#    notice, this list of conditions, and the following disclaimer.
478 -# 
479 -# 2. Redistributions in binary form must reproduce the above copyright
480 -#    notice, this list of conditions, and the following disclaimer in
481 -#    the documentation and/or other materials provided with the
482 -#    distribution.
483 -# 
484 -# 3. Digital Creations requests that attribution be given to Zope
485 -#    in any manner possible. Zope includes a "Powered by Zope"
486 -#    button that is installed by default. While it is not a license
487 -#    violation to remove this button, it is requested that the
488 -#    attribution remain. A significant investment has been put
489 -#    into Zope, and this effort will continue if the Zope community
490 -#    continues to grow. This is one way to assure that growth.
491 -# 
492 -# 4. All advertising materials and documentation mentioning
493 -#    features derived from or use of this software must display
494 -#    the following acknowledgement:
495 -# 
496 -#      "This product includes software developed by Digital Creations
497 -#      for use in the Z Object Publishing Environment
498 -#      (http://www.zope.org/)."
499 -# 
500 -#    In the event that the product being advertised includes an
501 -#    intact Zope distribution (with copyright and license included)
502 -#    then this clause is waived.
503 -# 
504 -# 5. Names associated with Zope or Digital Creations must not be used to
505 -#    endorse or promote products derived from this software without
506 -#    prior written permission from Digital Creations.
507 -# 
508 -# 6. Modified redistributions of any form whatsoever must retain
509 -#    the following acknowledgment:
510 -# 
511 -#      "This product includes software developed by Digital Creations
512 -#      for use in the Z Object Publishing Environment
513 -#      (http://www.zope.org/)."
514 -# 
515 -#    Intact (re-)distributions of any official Zope release do not
516 -#    require an external acknowledgement.
517 -# 
518 -# 7. Modifications are encouraged but must be packaged separately as
519 -#    patches to official Zope releases.  Distributions that do not
520 -#    clearly separate the patches from the original work must be clearly
521 -#    labeled as unofficial distributions.  Modifications which do not
522 -#    carry the name Zope may be packaged in any form, as long as they
523 -#    conform to all of the clauses above.
524 -# 
525 -# 
526 -# Disclaimer
527 -# 
528 -#   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
529 -#   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
530 -#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
531 -#   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
532 -#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
533 -#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
534 -#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
535 -#   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
536 -#   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
537 -#   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
538 -#   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
539 -#   SUCH DAMAGE.
540 -# 
541 -# 
542 -# This software consists of contributions made by Digital Creations and
543 -# many individuals on behalf of Digital Creations.  Specific
544 -# attributions are listed in the accompanying credits file.
545 -# 
546 +#
547 +# Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
548 +#
549 +# This software is subject to the provisions of the Zope Public License,
550 +# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
551 +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
552 +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
553 +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
554 +# FOR A PARTICULAR PURPOSE
555 +#
556  ##############################################################################
557  
558  ''' The Let tag was contributed to Zope by and is copyright, 1999
559      Phillip J. Eby.  Permission has been granted to release the Let tag
560      under the Zope Public License.
561 -    
562 +
563  
564     Let name=value...
565  
566 @@ -110,16 +38,17 @@
567     Variables are processed in sequence, so later assignments can
568     reference and/or overwrite the results of previous assignments,
569     as desired.
570 -''' 
571 +'''
572  
573 -from DT_Util import render_blocks, Eval, expr_globals, ParseError, regex, strip
574 +from DT_Util import render_blocks, Eval, ParseError
575  from DT_Util import str # Probably needed due to hysterical pickles.
576 +import re
577  
578  
579  class Let:
580      blockContinuations=()
581      name='let'
582 -    
583 +
584      def __init__(self, blocks):
585          tname, args, section = blocks[0]
586          self.__name__ = args
587 @@ -131,7 +60,7 @@
588              if expr[:1]=='"' and expr[-1:]=='"' and len(expr) > 1:
589                                 # expr shorthand
590                  expr=expr[1:-1]
591 -                try: args[i] = name, Eval(expr, expr_globals).eval
592 +                try: args[i] = name, Eval(expr).eval
593                  except SyntaxError, v:
594                      m,(huh,l,c,src) = v
595                      raise ParseError, (
596 @@ -149,32 +78,33 @@
597  
598      __call__ = render
599  
600 +
601  def parse_let_params(text,
602              result=None,
603              tag='let',
604 -            parmre=regex.compile(
605 -                '\([\0- ]*\([^\0- =\"]+\)=\([^\0- =\"]+\)\)'),
606 -            qparmre=regex.compile(
607 -                '\([\0- ]*\([^\0- =\"]+\)="\([^"]*\)\"\)'),
608 +            parmre=re.compile('([\000- ]*([^\000- ="]+)=([^\000- ="]+))'),
609 +            qparmre=re.compile('([\000- ]*([^\000- ="]+)="([^"]*)")'),
610              **parms):
611  
612      result=result or []
613  
614 -    if parmre.match(text) >= 0:
615 -        name=parmre.group(2)
616 -        value=parmre.group(3)
617 -        l=len(parmre.group(1))
618 -    elif qparmre.match(text) >= 0:
619 -        name=qparmre.group(2)
620 -        value='"%s"' % qparmre.group(3)
621 -        l=len(qparmre.group(1))
622 +    mo = parmre.match(text)
623 +    mo1= qparmre.match(text)
624 +
625 +    if mo is not None:
626 +        name=mo.group(2)
627 +        value=mo.group(3)
628 +        l=len(mo.group(1))
629 +    elif mo1 is not None:
630 +        name=mo1.group(2)
631 +        value='"%s"' % mo1.group(3)
632 +        l=len(mo1.group(1))
633      else:
634 -        if not text or not strip(text): return result
635 +        if not text or not text.strip(): return result
636          raise ParseError, ('invalid parameter: "%s"' % text, tag)
637 -    
638 +
639      result.append((name,value))
640  
641 -    text=strip(text[l:])
642 -    if text: return apply(parse_let_params,(text,result,tag),parms)
643 +    text=text[l:].strip()
644 +    if text: return parse_let_params(text,result,tag,**parms)
645      else: return result
646 -
647 Only in qm-2.3/qm/external/DocumentTemplate: DT_Let.py.orig
648 Only in qm-2.3/qm/external/DocumentTemplate: DT_Let.py.rej
649 Only in qm-2.3/qm/external/DocumentTemplate: DT_Let.py~
650 diff -ur qm-2.3.vanilla/qm/external/DocumentTemplate/DT_Return.py qm-2.3/qm/external/DocumentTemplate/DT_Return.py
651 --- qm-2.3.vanilla/qm/external/DocumentTemplate/DT_Return.py    2005-02-11 17:11:16.000000000 +0100
652 +++ qm-2.3/qm/external/DocumentTemplate/DT_Return.py    2007-07-23 22:13:09.000000000 +0200
653 @@ -85,7 +85,7 @@
654  __version__='$Revision$'[11:-2]
655  
656  from DT_Util import parse_params, name_param, html_quote, str
657 -import regex, string, sys, regex
658 +import string, sys
659  from string import find, split, join, atoi, rfind
660  
661  class ReturnTag: 
662 diff -ur qm-2.3.vanilla/qm/external/DocumentTemplate/DT_String.py qm-2.3/qm/external/DocumentTemplate/DT_String.py
663 --- qm-2.3.vanilla/qm/external/DocumentTemplate/DT_String.py    2005-02-11 17:11:16.000000000 +0100
664 +++ qm-2.3/qm/external/DocumentTemplate/DT_String.py    2007-07-23 22:13:09.000000000 +0200
665 @@ -1,91 +1,20 @@
666  ##############################################################################
667 -# 
668 -# Zope Public License (ZPL) Version 1.0
669 -# -------------------------------------
670 -# 
671 -# Copyright (c) Digital Creations.  All rights reserved.
672 -# 
673 -# This license has been certified as Open Source(tm).
674 -# 
675 -# Redistribution and use in source and binary forms, with or without
676 -# modification, are permitted provided that the following conditions are
677 -# met:
678 -# 
679 -# 1. Redistributions in source code must retain the above copyright
680 -#    notice, this list of conditions, and the following disclaimer.
681 -# 
682 -# 2. Redistributions in binary form must reproduce the above copyright
683 -#    notice, this list of conditions, and the following disclaimer in
684 -#    the documentation and/or other materials provided with the
685 -#    distribution.
686 -# 
687 -# 3. Digital Creations requests that attribution be given to Zope
688 -#    in any manner possible. Zope includes a "Powered by Zope"
689 -#    button that is installed by default. While it is not a license
690 -#    violation to remove this button, it is requested that the
691 -#    attribution remain. A significant investment has been put
692 -#    into Zope, and this effort will continue if the Zope community
693 -#    continues to grow. This is one way to assure that growth.
694 -# 
695 -# 4. All advertising materials and documentation mentioning
696 -#    features derived from or use of this software must display
697 -#    the following acknowledgement:
698 -# 
699 -#      "This product includes software developed by Digital Creations
700 -#      for use in the Z Object Publishing Environment
701 -#      (http://www.zope.org/)."
702 -# 
703 -#    In the event that the product being advertised includes an
704 -#    intact Zope distribution (with copyright and license included)
705 -#    then this clause is waived.
706 -# 
707 -# 5. Names associated with Zope or Digital Creations must not be used to
708 -#    endorse or promote products derived from this software without
709 -#    prior written permission from Digital Creations.
710 -# 
711 -# 6. Modified redistributions of any form whatsoever must retain
712 -#    the following acknowledgment:
713 -# 
714 -#      "This product includes software developed by Digital Creations
715 -#      for use in the Z Object Publishing Environment
716 -#      (http://www.zope.org/)."
717 -# 
718 -#    Intact (re-)distributions of any official Zope release do not
719 -#    require an external acknowledgement.
720 -# 
721 -# 7. Modifications are encouraged but must be packaged separately as
722 -#    patches to official Zope releases.  Distributions that do not
723 -#    clearly separate the patches from the original work must be clearly
724 -#    labeled as unofficial distributions.  Modifications which do not
725 -#    carry the name Zope may be packaged in any form, as long as they
726 -#    conform to all of the clauses above.
727 -# 
728 -# 
729 -# Disclaimer
730 -# 
731 -#   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
732 -#   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
733 -#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
734 -#   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
735 -#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
736 -#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
737 -#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
738 -#   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
739 -#   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
740 -#   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
741 -#   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
742 -#   SUCH DAMAGE.
743 -# 
744 -# 
745 -# This software consists of contributions made by Digital Creations and
746 -# many individuals on behalf of Digital Creations.  Specific
747 -# attributions are listed in the accompanying credits file.
748 -# 
749 +#
750 +# Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
751 +#
752 +# This software is subject to the provisions of the Zope Public License,
753 +# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
754 +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
755 +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
756 +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
757 +# FOR A PARTICULAR PURPOSE
758 +#
759  ##############################################################################
760  "$Id$"
761  
762 -from string import split, strip
763 -import regex, ts_regex
764 +import os
765 +import thread
766 +import re
767  
768  from DT_Util import ParseError, InstanceDict, TemplateDict, render_blocks, str
769  from DT_Var import Var, Call, Comment
770 @@ -109,7 +38,7 @@
771          %(name)s
772        %(in results)]
773  
774 -    """ 
775 +    """
776  
777      isDocTemp=1
778  
779 @@ -119,7 +48,7 @@
780      func_code.co_varnames='self','REQUEST'
781      func_code.co_argcount=2
782      func_code.__roles__=()
783 -    
784 +
785      func_defaults__roles__=()
786      func_defaults=()
787  
788 @@ -128,8 +57,8 @@
789  
790      parse_error__roles__=()
791      def parse_error(self, mess, tag, text, start):
792 -        raise ParseError, "%s, for tag %s, on line %s of %s<p>" % (
793 -            mess, self.errQuote(tag), len(split(text[:start],'\n')),
794 +        raise ParseError, "%s, for tag %s, on line %s of %s" % (
795 +            mess, self.errQuote(tag), len(text[:start].split('\n')),
796              self.errQuote(self.__name__))
797  
798      commands__roles__=()
799 @@ -154,35 +83,32 @@
800  
801      tagre__roles__=()
802      def tagre(self):
803 -        return regex.symcomp(
804 -            '%('                                     # beginning
805 -            '\(<name>[a-zA-Z0-9_/.-]+\)'                       # tag name
806 -            '\('
807 -            '[\0- ]+'                                # space after tag name
808 -            '\(<args>\([^)"]+\("[^"]*"\)?\)*\)'      # arguments
809 -            '\)?'
810 -            ')\(<fmt>[0-9]*[.]?[0-9]*[a-z]\|[]![]\)' # end
811 -            , regex.casefold) 
812 +        return re.compile(
813 +            '%\\('                                  # beginning
814 +            '(?P<name>[a-zA-Z0-9_/.-]+)'              # tag name
815 +            '('
816 +            '[\000- ]+'                             # space after tag name
817 +            '(?P<args>([^\\)"]+("[^"]*")?)*)'         # arguments
818 +            ')?'
819 +            '\\)(?P<fmt>[0-9]*[.]?[0-9]*[a-z]|[]![])' # end
820 +            , re.I)
821  
822      _parseTag__roles__=()
823 -    def _parseTag(self, tagre, command=None, sargs='', tt=type(())):
824 -        tag, args, command, coname = self.parseTag(tagre,command,sargs)
825 +    def _parseTag(self, match_ob, command=None, sargs='', tt=type(())):
826 +        tag, args, command, coname = self.parseTag(match_ob,command,sargs)
827          if type(command) is tt:
828              cname, module, name = command
829              d={}
830 -            # Subtlety: in these calls, globals() is not modified, but it
831 -            # provides module context for the import statement (so it knows
832 -            # to check the same directory as this file was found in).
833              try:
834 -                exec 'from %s import %s' % (module, name) in globals(), d
835 +                exec 'from %s import %s' % (module, name) in d
836              except ImportError:
837 -                exec 'from DocumentTemplate.%s import %s' % (module, name) in globals(), d
838 +                exec 'from DocumentTemplate.%s import %s' % (module, name) in d
839              command=d[name]
840              self.commands[cname]=command
841          return tag, args, command, coname
842  
843      parseTag__roles__=()
844 -    def parseTag(self, tagre, command=None, sargs=''):
845 +    def parseTag(self, match_ob, command=None, sargs=''):
846          """Parse a tag using an already matched re
847  
848          Return: tag, args, command, coname
849 @@ -194,8 +120,8 @@
850                 coname is the name of a continue tag (e.g. else)
851                   or None otherwise
852          """
853 -        tag, name, args, fmt =tagre.group(0, 'name', 'args', 'fmt')
854 -        args=args and strip(args) or ''
855 +        tag, name, args, fmt = match_ob.group(0, 'name', 'args', 'fmt')
856 +        args=args and args.strip() or ''
857  
858          if fmt==']':
859              if not command or name != command.name:
860 @@ -223,17 +149,18 @@
861              return tag, args, Var, None
862  
863      varExtra__roles__=()
864 -    def varExtra(self,tagre):
865 -        return tagre.group('fmt')
866 +    def varExtra(self, match_ob):
867 +        return match_ob.group('fmt')
868  
869      parse__roles__=()
870      def parse(self,text,start=0,result=None,tagre=None):
871          if result is None: result=[]
872          if tagre is None: tagre=self.tagre()
873 -        l=tagre.search(text,start)
874 -        while l >= 0:
875 +        mo = tagre.search(text,start)
876 +        while mo :
877 +            l = mo.start(0)
878  
879 -            try: tag, args, command, coname = self._parseTag(tagre)
880 +            try: tag, args, command, coname = self._parseTag(mo)
881              except ParseError, m: self.parse_error(m[0],m[1],text,l)
882  
883              s=text[start:l]
884 @@ -245,23 +172,25 @@
885                                         tag, l, args, command)
886              else:
887                  try:
888 -                    if command is Var: r=command(args, self.varExtra(tagre))
889 +                    if command is Var: r=command(args, self.varExtra(mo))
890                      else: r=command(args)
891                      if hasattr(r,'simple_form'): r=r.simple_form
892                      result.append(r)
893                  except ParseError, m: self.parse_error(m[0],tag,text,l)
894  
895 -            l=tagre.search(text,start)
896 +            mo = tagre.search(text,start)
897  
898          text=text[start:]
899          if text: result.append(text)
900          return result
901  
902      skip_eol__roles__=()
903 -    def skip_eol(self, text, start, eol=regex.compile('[ \t]*\n')):
904 +    def skip_eol(self, text, start, eol=re.compile('[ \t]*\n')):
905          # if block open is followed by newline, then skip past newline
906 -        l=eol.match(text,start)
907 -        if l > 0: start=start+l
908 +        mo =eol.match(text,start)
909 +        if mo is not None:
910 +            start = start + mo.end(0) - mo.start(0)
911 +
912          return start
913  
914      parse_block__roles__=()
915 @@ -277,12 +206,13 @@
916          sa=sargs
917          while 1:
918  
919 -            l=tagre.search(text,start)
920 -            if l < 0: self.parse_error('No closing tag', stag, text, sloc)
921 +            mo = tagre.search(text,start)
922 +            if mo is None: self.parse_error('No closing tag', stag, text, sloc)
923 +            l = mo.start(0)
924  
925 -            try: tag, args, command, coname= self._parseTag(tagre,scommand,sa)
926 +            try: tag, args, command, coname= self._parseTag(mo,scommand,sa)
927              except ParseError, m: self.parse_error(m[0],m[1], text, l)
928 -            
929 +
930              if command:
931                  start=l+len(tag)
932                  if hasattr(command, 'blockContinuations'):
933 @@ -295,7 +225,7 @@
934                  section._v_blocks=section.blocks=self.parse(text[:l],sstart)
935                  section._v_cooked=None
936                  blocks.append((tname,sargs,section))
937 -    
938 +
939                  start=self.skip_eol(text,l+len(tag))
940  
941                  if coname:
942 @@ -315,10 +245,11 @@
943      parse_close__roles__=()
944      def parse_close(self, text, start, tagre, stag, sloc, scommand, sa):
945          while 1:
946 -            l=tagre.search(text,start)
947 -            if l < 0: self.parse_error('No closing tag', stag, text, sloc)
948 +            mo = tagre.search(text,start)
949 +            if mo is None: self.parse_error('No closing tag', stag, text, sloc)
950 +            l = mo.start(0)
951  
952 -            try: tag, args, command, coname= self._parseTag(tagre,scommand,sa)
953 +            try: tag, args, command, coname= self._parseTag(mo,scommand,sa)
954              except ParseError, m: self.parse_error(m[0],m[1], text, l)
955  
956              start=l+len(tag)
957 @@ -386,7 +317,7 @@
958          """
959          if mapping is not None or vars:
960              self.initvars(mapping, vars)
961 -        if source_string is not None: 
962 +        if source_string is not None:
963              self.raw=source_string
964          self.cook()
965  
966 @@ -404,7 +335,7 @@
967  
968      cook__roles__=()
969      def cook(self,
970 -             cooklock=ts_regex.allocate_lock(),
971 +             cooklock=thread.allocate_lock(),
972               ):
973          cooklock.acquire()
974          try:
975 @@ -442,13 +373,13 @@
976          containing values to be looked up.  Values will be looked up
977          using getattr, so inheritence of values is supported.  Note
978          that names beginning with '_' will not be looked up from the
979 -        client. 
980 +        client.
981  
982          The optional argument, 'mapping' is used to specify a mapping
983          object containing values to be inserted.
984  
985          Values to be inserted may also be specified using keyword
986 -        arguments. 
987 +        arguments.
988  
989          Values will be inserted from one of several sources.  The
990          sources, in the order in which they are consulted, are:
991 @@ -463,7 +394,7 @@
992               created, and
993  
994            o  The 'mapping' argument provided when the template was
995 -             created. 
996 +             created.
997  
998          '''
999          # print '============================================================'
1000 @@ -526,8 +457,8 @@
1001                  # otherwise its just a normal client object.
1002                  push(InstanceDict(client, md)) # Circ. Ref. 8-|
1003                  pushed=pushed+1
1004 -                
1005 -        if self._vars: 
1006 +
1007 +        if self._vars:
1008              push(self._vars)
1009              pushed=pushed+1
1010  
1011 @@ -565,7 +496,7 @@
1012  class FileMixin:
1013      # Mix-in class to abstract certain file-related attributes
1014      edited_source=''
1015 -    
1016 +
1017      def __init__(self, file_name='', mapping=None, __name__='', **vars):
1018          """\
1019          Create a document template based on a named file.
1020 diff -ur qm-2.3.vanilla/qm/external/DocumentTemplate/DT_Util.py qm-2.3/qm/external/DocumentTemplate/DT_Util.py
1021 --- qm-2.3.vanilla/qm/external/DocumentTemplate/DT_Util.py      2005-02-14 08:01:54.000000000 +0100
1022 +++ qm-2.3/qm/external/DocumentTemplate/DT_Util.py      2007-07-23 22:13:09.000000000 +0200
1023 @@ -1,92 +1,20 @@
1024  ##############################################################################
1025 -# 
1026 -# Zope Public License (ZPL) Version 1.0
1027 -# -------------------------------------
1028 -# 
1029 -# Copyright (c) Digital Creations.  All rights reserved.
1030 -# 
1031 -# This license has been certified as Open Source(tm).
1032 -# 
1033 -# Redistribution and use in source and binary forms, with or without
1034 -# modification, are permitted provided that the following conditions are
1035 -# met:
1036 -# 
1037 -# 1. Redistributions in source code must retain the above copyright
1038 -#    notice, this list of conditions, and the following disclaimer.
1039 -# 
1040 -# 2. Redistributions in binary form must reproduce the above copyright
1041 -#    notice, this list of conditions, and the following disclaimer in
1042 -#    the documentation and/or other materials provided with the
1043 -#    distribution.
1044 -# 
1045 -# 3. Digital Creations requests that attribution be given to Zope
1046 -#    in any manner possible. Zope includes a "Powered by Zope"
1047 -#    button that is installed by default. While it is not a license
1048 -#    violation to remove this button, it is requested that the
1049 -#    attribution remain. A significant investment has been put
1050 -#    into Zope, and this effort will continue if the Zope community
1051 -#    continues to grow. This is one way to assure that growth.
1052 -# 
1053 -# 4. All advertising materials and documentation mentioning
1054 -#    features derived from or use of this software must display
1055 -#    the following acknowledgement:
1056 -# 
1057 -#      "This product includes software developed by Digital Creations
1058 -#      for use in the Z Object Publishing Environment
1059 -#      (http://www.zope.org/)."
1060 -# 
1061 -#    In the event that the product being advertised includes an
1062 -#    intact Zope distribution (with copyright and license included)
1063 -#    then this clause is waived.
1064 -# 
1065 -# 5. Names associated with Zope or Digital Creations must not be used to
1066 -#    endorse or promote products derived from this software without
1067 -#    prior written permission from Digital Creations.
1068 -# 
1069 -# 6. Modified redistributions of any form whatsoever must retain
1070 -#    the following acknowledgment:
1071 -# 
1072 -#      "This product includes software developed by Digital Creations
1073 -#      for use in the Z Object Publishing Environment
1074 -#      (http://www.zope.org/)."
1075 -# 
1076 -#    Intact (re-)distributions of any official Zope release do not
1077 -#    require an external acknowledgement.
1078 -# 
1079 -# 7. Modifications are encouraged but must be packaged separately as
1080 -#    patches to official Zope releases.  Distributions that do not
1081 -#    clearly separate the patches from the original work must be clearly
1082 -#    labeled as unofficial distributions.  Modifications which do not
1083 -#    carry the name Zope may be packaged in any form, as long as they
1084 -#    conform to all of the clauses above.
1085 -# 
1086 -# 
1087 -# Disclaimer
1088 -# 
1089 -#   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
1090 -#   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1091 -#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1092 -#   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
1093 -#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1094 -#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1095 -#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
1096 -#   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1097 -#   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
1098 -#   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
1099 -#   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1100 -#   SUCH DAMAGE.
1101 -# 
1102 -# 
1103 -# This software consists of contributions made by Digital Creations and
1104 -# many individuals on behalf of Digital Creations.  Specific
1105 -# attributions are listed in the accompanying credits file.
1106 -# 
1107 +#
1108 +# Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
1109 +#
1110 +# This software is subject to the provisions of the Zope Public License,
1111 +# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
1112 +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
1113 +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1114 +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
1115 +# FOR A PARTICULAR PURPOSE
1116 +#
1117  ##############################################################################
1118 -'''$Id$''' 
1119 -__version__='$Revision$'[11:-2]
1120 -
1121 -import regex, string, math, os
1122 -from string import strip, join, atoi, lower, split, find
1123 +"""DTML Utilities
1124 +  
1125 +$Id$"""
1126
1127 +import re
1128  import VSEval
1129  
1130  str=__builtins__['str'] # Waaaaa, waaaaaaaa needed for pickling waaaaa
1131 @@ -103,17 +31,18 @@
1132                         (('"'),    '&quot;'))): #"
1133          text=str(v)
1134          for re,name in character_entities:
1135 -            if find(text, re) >= 0: text=join(split(text,re),name)
1136 +            if text.find(re) >= 0: text=text.split(re).join(name)
1137          return text
1138  
1139  def int_param(params,md,name,default=0, st=type('')):
1140 -    try: v=params[name]
1141 -    except: v=default
1142 +    v = params.get(name, default)
1143      if v:
1144 -        try: v=atoi(v)
1145 +        try:
1146 +            v = int(v)
1147          except:
1148 -            v=md[v]
1149 -            if type(v) is st: v=atoi(v)
1150 +            v = md[v]
1151 +            if isinstance(v, str):
1152 +                v = int(v)
1153      return v or 0
1154  
1155  _marker=[]
1156 @@ -449,14 +378,10 @@
1157  def parse_params(text,
1158                   result=None,
1159                   tag='',
1160 -                 unparmre=regex.compile(
1161 -                     '\([\0- ]*\([^\0- =\"]+\)\)'),
1162 -                 qunparmre=regex.compile(
1163 -                     '\([\0- ]*\("[^"]*"\)\)'),
1164 -                 parmre=regex.compile(
1165 -                     '\([\0- ]*\([^\0- =\"]+\)=\([^\0- =\"]+\)\)'),
1166 -                 qparmre=regex.compile(
1167 -                     '\([\0- ]*\([^\0- =\"]+\)="\([^"]*\)\"\)'),
1168 +                 unparmre=re.compile('([\000- ]*([^\000- ="]+))'),
1169 +                 qunparmre=re.compile('([\000- ]*("[^"]*"))'),
1170 +                 parmre=re.compile('([\000- ]*([^\000- ="]+)=([^\000- ="]+))'),
1171 +                 qparmre=re.compile('([\000- ]*([^\000- ="]+)="([^"]*)")'),
1172                   **parms):
1173  
1174      """Parse tag parameters
1175 @@ -482,39 +407,47 @@
1176  
1177      result=result or {}
1178  
1179 -    if parmre.match(text) >= 0:
1180 -        name=lower(parmre.group(2))
1181 -        value=parmre.group(3)
1182 -        l=len(parmre.group(1))
1183 -    elif qparmre.match(text) >= 0:
1184 -        name=lower(qparmre.group(2))
1185 -        value=qparmre.group(3)
1186 -        l=len(qparmre.group(1))
1187 -    elif unparmre.match(text) >= 0:
1188 -        name=unparmre.group(2)
1189 -        l=len(unparmre.group(1))
1190 +    # HACK - we precalculate all matches. Maybe we don't need them
1191 +    # all. This should be fixed for performance issues
1192 +
1193 +    mo_p = parmre.match(text)
1194 +    mo_q = qparmre.match(text)
1195 +    mo_unp = unparmre.match(text)
1196 +    mo_unq = qunparmre.match(text)
1197 +
1198 +    if mo_p:
1199 +        name=mo_p.group(2).lower()
1200 +        value=mo_p.group(3)
1201 +        l=len(mo_p.group(1))
1202 +    elif mo_q:
1203 +        name=mo_q.group(2).lower()
1204 +        value=mo_q.group(3)
1205 +        l=len(mo_q.group(1))
1206 +    elif mo_unp:
1207 +        name=mo_unp.group(2)
1208 +        l=len(mo_unp.group(1))
1209          if result:
1210              if parms.has_key(name):
1211                  if parms[name] is None: raise ParseError, (
1212                      'Attribute %s requires a value' % name, tag)
1213 -                    
1214 +
1215                  result[name]=parms[name]
1216              else: raise ParseError, (
1217                  'Invalid attribute name, "%s"' % name, tag)
1218          else:
1219              result['']=name
1220 -        return apply(parse_params,(text[l:],result),parms)
1221 -    elif qunparmre.match(text) >= 0:
1222 -        name=qunparmre.group(2)
1223 -        l=len(qunparmre.group(1))
1224 +        return parse_params(text[l:],result,**parms)
1225 +    elif mo_unq:
1226 +        name=mo_unq.group(2)
1227 +        l=len(mo_unq.group(1))
1228          if result: raise ParseError, (
1229              'Invalid attribute name, "%s"' % name, tag)
1230          else: result['']=name
1231 -        return apply(parse_params,(text[l:],result),parms)
1232 +        return parse_params(text[l:],result,**parms)
1233      else:
1234 -        if not text or not strip(text): return result
1235 +        if not text or not text.strip(): return result
1236          raise ParseError, ('invalid parameter: "%s"' % text, tag)
1237 -    
1238 +
1239      if not parms.has_key(name):
1240          raise ParseError, (
1241              'Invalid attribute name, "%s"' % name, tag)
1242 @@ -524,9 +457,9 @@
1243          if type(p) is not ListType or p:
1244              raise ParseError, (
1245                  'Duplicate values for attribute "%s"' % name, tag)
1246 -            
1247 +
1248      result[name]=value
1249  
1250 -    text=strip(text[l:])
1251 -    if text: return apply(parse_params,(text,result),parms)
1252 +    text=text[l:].strip()
1253 +    if text: return parse_params(text,result,**parms)
1254      else: return result
1255 diff -ur qm-2.3.vanilla/qm/external/DocumentTemplate/DT_Var.py qm-2.3/qm/external/DocumentTemplate/DT_Var.py
1256 --- qm-2.3.vanilla/qm/external/DocumentTemplate/DT_Var.py       2005-02-11 17:11:16.000000000 +0100
1257 +++ qm-2.3/qm/external/DocumentTemplate/DT_Var.py       2007-07-23 22:13:09.000000000 +0200
1258 @@ -221,8 +221,7 @@
1259  __version__='$Revision$'[11:-2]
1260  
1261  from DT_Util import parse_params, name_param, html_quote, str
1262 -import regex, string, sys, regex
1263 -from string import find, split, join, atoi, rfind
1264 +import string, re, sys
1265  from urllib import quote, quote_plus
1266  
1267  class Var: 
1268 @@ -322,13 +321,13 @@
1269  
1270          if have_arg('size'):
1271              size=args['size']
1272 -            try: size=atoi(size)
1273 +            try: size=int(size)
1274              except: raise 'Document Error',(
1275                  '''a <code>size</code> attribute was used in a <code>var</code>
1276                  tag with a non-integer value.''')
1277              if len(val) > size:
1278                  val=val[:size]
1279 -                l=rfind(val,' ')
1280 +                l=val.rfind(' ')
1281                  if l > size/2:
1282                      val=val[:l+1]
1283                  if have_arg('etc'): l=args['etc']
1284 @@ -360,8 +359,8 @@
1285  
1286  def newline_to_br(v, name='(Unknown name)', md={}):
1287      v=str(v)
1288 -    if find(v,'\r') >= 0: v=join(split(v,'\r'),'')
1289 -    if find(v,'\n') >= 0: v=join(split(v,'\n'),'<br>\n')
1290 +    if v.find('\r') >= 0: v=''.join(v.split('\r'))
1291 +    if v.find('\n') >= 0: v='<br />\n'.join(v.split('\n'))
1292      return v
1293  
1294  def whole_dollars(v, name='(Unknown name)', md={}):
1295 @@ -373,19 +372,20 @@
1296      except: return ''
1297  
1298  def thousands_commas(v, name='(Unknown name)', md={},
1299 -                     thou=regex.compile(
1300 -                         "\([0-9]\)\([0-9][0-9][0-9]\([,.]\|$\)\)").search):
1301 +                     thou=re.compile(
1302 +                         r"([0-9])([0-9][0-9][0-9]([,.]|$))").search):
1303      v=str(v)
1304 -    vl=split(v,'.')
1305 +    vl=v.split('.')
1306      if not vl: return v
1307      v=vl[0]
1308      del vl[0]
1309 -    if vl: s='.'+join(vl,'.')
1310 +    if vl: s='.'+'.'.join(vl)
1311      else: s=''
1312 -    l=thou(v)
1313 -    while l >= 0:
1314 +    mo=thou(v)
1315 +    while mo is not None:
1316 +        l = mo.start(0)
1317          v=v[:l+1]+','+v[l+1:]
1318 -        l=thou(v)
1319 +        mo=thou(v)
1320      return v+s
1321      
1322  def whole_dollars_with_commas(v, name='(Unknown name)', md={}):
1323 @@ -416,7 +416,7 @@
1324      This is needed to securely insert values into sql
1325      string literals in templates that generate sql.
1326      """
1327 -    if find(v,"'") >= 0: return join(split(v,"'"),"''")
1328 +    if v.find("'") >= 0: return v.replace("'", "''")
1329      return v
1330  
1331  special_formats={
1332 @@ -437,7 +437,7 @@
1333      }
1334  
1335  def spacify(val):
1336 -    if find(val,'_') >= 0: val=join(split(val,'_'))
1337 +    if val.find('_') >= 0: val=val.replace('_', ' ')
1338      return val
1339  
1340  modifiers=(html_quote, url_quote, url_quote_plus, newline_to_br,
1341 diff -ur qm-2.3.vanilla/qm/external/DocumentTemplate/__init__.py qm-2.3/qm/external/DocumentTemplate/__init__.py
1342 --- qm-2.3.vanilla/qm/external/DocumentTemplate/__init__.py     2005-02-11 17:11:16.000000000 +0100
1343 +++ qm-2.3/qm/external/DocumentTemplate/__init__.py     2007-07-23 22:13:09.000000000 +0200
1344 @@ -1,86 +1,14 @@
1345  ##############################################################################
1346 -# 
1347 -# Zope Public License (ZPL) Version 1.0
1348 -# -------------------------------------
1349 -# 
1350 -# Copyright (c) Digital Creations.  All rights reserved.
1351 -# 
1352 -# This license has been certified as Open Source(tm).
1353 -# 
1354 -# Redistribution and use in source and binary forms, with or without
1355 -# modification, are permitted provided that the following conditions are
1356 -# met:
1357 -# 
1358 -# 1. Redistributions in source code must retain the above copyright
1359 -#    notice, this list of conditions, and the following disclaimer.
1360 -# 
1361 -# 2. Redistributions in binary form must reproduce the above copyright
1362 -#    notice, this list of conditions, and the following disclaimer in
1363 -#    the documentation and/or other materials provided with the
1364 -#    distribution.
1365 -# 
1366 -# 3. Digital Creations requests that attribution be given to Zope
1367 -#    in any manner possible. Zope includes a "Powered by Zope"
1368 -#    button that is installed by default. While it is not a license
1369 -#    violation to remove this button, it is requested that the
1370 -#    attribution remain. A significant investment has been put
1371 -#    into Zope, and this effort will continue if the Zope community
1372 -#    continues to grow. This is one way to assure that growth.
1373 -# 
1374 -# 4. All advertising materials and documentation mentioning
1375 -#    features derived from or use of this software must display
1376 -#    the following acknowledgement:
1377 -# 
1378 -#      "This product includes software developed by Digital Creations
1379 -#      for use in the Z Object Publishing Environment
1380 -#      (http://www.zope.org/)."
1381 -# 
1382 -#    In the event that the product being advertised includes an
1383 -#    intact Zope distribution (with copyright and license included)
1384 -#    then this clause is waived.
1385 -# 
1386 -# 5. Names associated with Zope or Digital Creations must not be used to
1387 -#    endorse or promote products derived from this software without
1388 -#    prior written permission from Digital Creations.
1389 -# 
1390 -# 6. Modified redistributions of any form whatsoever must retain
1391 -#    the following acknowledgment:
1392 -# 
1393 -#      "This product includes software developed by Digital Creations
1394 -#      for use in the Z Object Publishing Environment
1395 -#      (http://www.zope.org/)."
1396 -# 
1397 -#    Intact (re-)distributions of any official Zope release do not
1398 -#    require an external acknowledgement.
1399 -# 
1400 -# 7. Modifications are encouraged but must be packaged separately as
1401 -#    patches to official Zope releases.  Distributions that do not
1402 -#    clearly separate the patches from the original work must be clearly
1403 -#    labeled as unofficial distributions.  Modifications which do not
1404 -#    carry the name Zope may be packaged in any form, as long as they
1405 -#    conform to all of the clauses above.
1406 -# 
1407 -# 
1408 -# Disclaimer
1409 -# 
1410 -#   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
1411 -#   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1412 -#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1413 -#   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
1414 -#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1415 -#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1416 -#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
1417 -#   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1418 -#   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
1419 -#   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
1420 -#   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1421 -#   SUCH DAMAGE.
1422 -# 
1423 -# 
1424 -# This software consists of contributions made by Digital Creations and
1425 -# many individuals on behalf of Digital Creations.  Specific
1426 -# attributions are listed in the accompanying credits file.
1427 -# 
1428 +#
1429 +# Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
1430 +#
1431 +# This software is subject to the provisions of the Zope Public License,
1432 +# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
1433 +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
1434 +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1435 +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
1436 +# FOR A PARTICULAR PURPOSE
1437 +#
1438  ##############################################################################
1439  __doc__='''Package wrapper for Document Template
1440  
1441 @@ -90,8 +18,4 @@
1442  $Id$'''
1443  __version__='$Revision$'[11:-2]
1444  
1445 -try:
1446 -    import ExtensionClass # work-around for import bug.
1447 -except ImportError: pass
1448  from DocumentTemplate import String, File, HTML, HTMLDefault, HTMLFile
1449 -from DocumentTemplate import html_quote
1450 diff -ur qm-2.3.vanilla/qm/external/DocumentTemplate/ts_regex.py qm-2.3/qm/external/DocumentTemplate/ts_regex.py
1451 --- qm-2.3.vanilla/qm/external/DocumentTemplate/ts_regex.py     2005-02-11 17:11:16.000000000 +0100
1452 +++ qm-2.3/qm/external/DocumentTemplate/ts_regex.py     2007-07-23 22:13:09.000000000 +0200
1453 @@ -1,215 +0,0 @@
1454 -##############################################################################
1455 -# 
1456 -# Zope Public License (ZPL) Version 1.0
1457 -# -------------------------------------
1458 -# 
1459 -# Copyright (c) Digital Creations.  All rights reserved.
1460 -# 
1461 -# This license has been certified as Open Source(tm).
1462 -# 
1463 -# Redistribution and use in source and binary forms, with or without
1464 -# modification, are permitted provided that the following conditions are
1465 -# met:
1466 -# 
1467 -# 1. Redistributions in source code must retain the above copyright
1468 -#    notice, this list of conditions, and the following disclaimer.
1469 -# 
1470 -# 2. Redistributions in binary form must reproduce the above copyright
1471 -#    notice, this list of conditions, and the following disclaimer in
1472 -#    the documentation and/or other materials provided with the
1473 -#    distribution.
1474 -# 
1475 -# 3. Digital Creations requests that attribution be given to Zope
1476 -#    in any manner possible. Zope includes a "Powered by Zope"
1477 -#    button that is installed by default. While it is not a license
1478 -#    violation to remove this button, it is requested that the
1479 -#    attribution remain. A significant investment has been put
1480 -#    into Zope, and this effort will continue if the Zope community
1481 -#    continues to grow. This is one way to assure that growth.
1482 -# 
1483 -# 4. All advertising materials and documentation mentioning
1484 -#    features derived from or use of this software must display
1485 -#    the following acknowledgement:
1486 -# 
1487 -#      "This product includes software developed by Digital Creations
1488 -#      for use in the Z Object Publishing Environment
1489 -#      (http://www.zope.org/)."
1490 -# 
1491 -#    In the event that the product being advertised includes an
1492 -#    intact Zope distribution (with copyright and license included)
1493 -#    then this clause is waived.
1494 -# 
1495 -# 5. Names associated with Zope or Digital Creations must not be used to
1496 -#    endorse or promote products derived from this software without
1497 -#    prior written permission from Digital Creations.
1498 -# 
1499 -# 6. Modified redistributions of any form whatsoever must retain
1500 -#    the following acknowledgment:
1501 -# 
1502 -#      "This product includes software developed by Digital Creations
1503 -#      for use in the Z Object Publishing Environment
1504 -#      (http://www.zope.org/)."
1505 -# 
1506 -#    Intact (re-)distributions of any official Zope release do not
1507 -#    require an external acknowledgement.
1508 -# 
1509 -# 7. Modifications are encouraged but must be packaged separately as
1510 -#    patches to official Zope releases.  Distributions that do not
1511 -#    clearly separate the patches from the original work must be clearly
1512 -#    labeled as unofficial distributions.  Modifications which do not
1513 -#    carry the name Zope may be packaged in any form, as long as they
1514 -#    conform to all of the clauses above.
1515 -# 
1516 -# 
1517 -# Disclaimer
1518 -# 
1519 -#   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
1520 -#   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1521 -#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1522 -#   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
1523 -#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1524 -#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1525 -#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
1526 -#   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1527 -#   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
1528 -#   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
1529 -#   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1530 -#   SUCH DAMAGE.
1531 -# 
1532 -# 
1533 -# This software consists of contributions made by Digital Creations and
1534 -# many individuals on behalf of Digital Creations.  Specific
1535 -# attributions are listed in the accompanying credits file.
1536 -# 
1537 -##############################################################################
1538 -"""Provide a thread-safe interface to regex
1539 -"""
1540 -import regex, regsub #, Sync
1541 -from regex import *
1542 -from regsub import split, sub, gsub, splitx, capwords
1543 -
1544 -try: 
1545 -    import thread
1546 -except:
1547 -    class allocate_lock:
1548 -        def acquire(*args): pass
1549 -        def release(*args): pass
1550 -
1551 -else:
1552 -    class SafeFunction:
1553 -        _l=thread.allocate_lock()
1554 -        _a=_l.acquire
1555 -        _r=_l.release
1556 -
1557 -        def __init__(self, f):
1558 -            self._f=f
1559 -
1560 -        def __call__(self, *args, **kw):
1561 -            self._a()
1562 -            try: return apply(self._f, args, kw)
1563 -            finally: self._r()
1564 -
1565 -    split=SafeFunction(split)
1566 -    sub=SafeFunction(sub)
1567 -    gsub=SafeFunction(gsub)
1568 -    splitx=SafeFunction(splitx)
1569 -    capwords=SafeFunction(capwords)
1570 -
1571 -    allocate_lock=thread.allocate_lock
1572 -
1573 -class compile:
1574 -
1575 -    _r=None
1576 -    groupindex=None
1577 -
1578 -    def __init__(self, *args):
1579 -        self._r=r=apply(regex.compile,args)
1580 -        self._init(r)
1581 -
1582 -    def _init(self, r):
1583 -        lock=allocate_lock()
1584 -        self.__a=lock.acquire
1585 -        self.__r=lock.release
1586 -        self.translate=r.translate
1587 -        self.givenpat=r.givenpat
1588 -        self.realpat=r.realpat
1589 -
1590 -    def match(self, string, pos=0):
1591 -        self.__a()
1592 -        try: return self._r.match(string, pos)
1593 -        finally: self.__r()
1594 -
1595 -    def search(self, string, pos=0):
1596 -        self.__a()
1597 -        try: return self._r.search(string, pos)
1598 -        finally: self.__r()
1599 -        
1600 -    def search_group(self, str, group, pos=0):
1601 -        """Search a string for a pattern.
1602 -
1603 -        If the pattern was not found, then None is returned,
1604 -        otherwise, the location where the pattern was found,
1605 -        as well as any specified group are returned.
1606 -        """
1607 -        self.__a()
1608 -        try:
1609 -            r=self._r
1610 -            l=r.search(str, pos)
1611 -            if l < 0: return None
1612 -            return l, apply(r.group, group)
1613 -        finally: self.__r()
1614 -
1615 -    def match_group(self, str, group, pos=0):
1616 -        """Match a pattern against a string
1617 -
1618 -        If the string does not match the pattern, then None is
1619 -        returned, otherwise, the length of the match, as well
1620 -        as any specified group are returned.
1621 -        """
1622 -        self.__a()
1623 -        try:
1624 -            r=self._r
1625 -            l=r.match(str, pos)
1626 -            if l < 0: return None
1627 -            return l, apply(r.group, group)
1628 -        finally: self.__r()
1629 -
1630 -    def search_regs(self, str, pos=0):
1631 -        """Search a string for a pattern.
1632 -
1633 -        If the pattern was not found, then None is returned,
1634 -        otherwise, the 'regs' attribute of the expression is
1635 -        returned.
1636 -        """
1637 -        self.__a()
1638 -        try:
1639 -            r=self._r
1640 -            r.search(str, pos)
1641 -            return r.regs
1642 -        finally: self.__r()
1643 -
1644 -    def match_regs(self, str, pos=0):
1645 -        """Match a pattern against a string
1646 -
1647 -        If the string does not match the pattern, then None is
1648 -        returned, otherwise, the 'regs' attribute of the expression is
1649 -        returned.
1650 -        """
1651 -        self.__a()
1652 -        try:
1653 -            r=self._r
1654 -            r.match(str, pos)
1655 -            return r.regs
1656 -        finally: self.__r()
1657 -
1658 -class symcomp(compile):
1659 -
1660 -    def __init__(self, *args):
1661 -        self._r=r=apply(regex.symcomp,args)
1662 -        self._init(r)
1663 -        self.groupindex=r.groupindex
1664 -
1665 -
1666 -
1667 -
1668 -        
1669 diff -ur qm-2.3.vanilla/qm/web.py qm-2.3/qm/web.py
1670 --- qm-2.3.vanilla/qm/web.py    2005-02-25 12:02:22.000000000 +0100
1671 +++ qm-2.3/qm/web.py    2007-07-23 22:13:09.000000000 +0200
1672 @@ -46,6 +46,7 @@
1673  import random
1674  
1675  import qm.external.DocumentTemplate as DocumentTemplate
1676 +sys.path.insert(1, os.path.dirname(os.path.dirname(DocumentTemplate.__file__)))
1677  
1678  ########################################################################
1679  # constants
This page took 0.194185 seconds and 3 git commands to generate.