[Zope3-checkins] CVS: Zope3/src/zope/documenttemplate - __init__.py:1.1.2.1 documenttemplate.py:1.1.2.1 dt_html.py:1.1.2.1 dt_if.py:1.1.2.1 dt_in.py:1.1.2.1 dt_insv.py:1.1.2.1 dt_let.py:1.1.2.1 dt_raise.py:1.1.2.1 dt_return.py:1.1.2.1 dt_string.py:1.1.2.1 dt_try.py:1.1.2.1 dt_util.py:1.1.2.1 dt_var.py:1.1.2.1 dt_with.py:1.1.2.1 pdocumenttemplate.py:1.1.2.1
Jim Fulton
jim@zope.com
Mon, 23 Dec 2002 14:32:48 -0500
Update of /cvs-repository/Zope3/src/zope/documenttemplate
In directory cvs.zope.org:/tmp/cvs-serv19908/zope/documenttemplate
Added Files:
Tag: NameGeddon-branch
__init__.py documenttemplate.py dt_html.py dt_if.py dt_in.py
dt_insv.py dt_let.py dt_raise.py dt_return.py dt_string.py
dt_try.py dt_util.py dt_var.py dt_with.py pdocumenttemplate.py
Log Message:
Initial renaming before debugging
=== Added File Zope3/src/zope/documenttemplate/__init__.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Package wrapper for Document Template
This wrapper allows the (now many) document template modules to be
segregated in a separate package.
$Id: __init__.py,v 1.1.2.1 2002/12/23 19:32:46 jim Exp $
"""
from zope.documenttemplate.documenttemplate import String, HTML
from zope.documenttemplate.documenttemplate import html_quote
=== Added File Zope3/src/zope/documenttemplate/documenttemplate.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
'''Document templates with fill-in fields
Document templates provide for creation of textual documents, such as
HTML pages, from template source by inserting data from python objects
and name-spaces.
When a document template is created, a collection of default values to
be inserted may be specified with a mapping object and with keyword
arguments.
A document templated may be called to create a document with values
inserted. When called, an instance, a mapping object, and keyword
arguments may be specified to provide values to be inserted. If an
instance is provided, the document template will try to look up values
in the instance using getattr, so inheritence of values is supported.
If an inserted value is a function, method, or class, then an attempt
will be made to call the object to obtain values. This allows
instance methods to be included in documents.
Document templates masquerade as functions, so the python object
publisher (Bobo) will call templates that are stored as instances of
published objects. Bobo will pass the object the template was found in
and the HTTP request object.
Two source formats are supported:
Extended Python format strings (EPFS) --
This format is based on the insertion by name format strings
of python with additional format characters, '[' and ']' to
indicate block boundaries. In addition, parameters may be
used within formats to control how insertion is done.
For example:
%%(date fmt=DayOfWeek upper)s
causes the contents of variable 'date' to be inserted using
custom format 'DayOfWeek' and with all lower case letters
converted to upper case.
HTML --
This format uses HTML server-side-include syntax with
commands for inserting text. Parameters may be included to
customize the operation of a command.
For example:
<dtml-var total fmt=12.2f>
is used to insert the variable 'total' with the C format
'12.2f'.
Document templates support conditional and sequence insertion
Document templates extend python string substitition rules with a
mechanism that allows conditional insertion of template text and that
allows sequences to be inserted with element-wise insertion of
template text.
Document Templates may be created 2 ways by default:
DocumentTemplate.String -- Creates a document templated from a
string using an extended form of python string formatting.
DocumentTemplate.HTML -- Creates a document templated from a
string using HTML server-side-include rather than
python-format-string syntax.
$Id: documenttemplate.py,v 1.1.2.1 2002/12/23 19:32:46 jim Exp $
'''
ParseError='Document Template Parse Error'
from zope.documenttemplate.dt_string import String
from zope.documenttemplate.dt_html import HTML
from zope.documenttemplate.dt_util import html_quote
=== Added File Zope3/src/zope/documenttemplate/dt_html.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""HTML formated DocumentTemplates
$Id: dt_html.py,v 1.1.2.1 2002/12/23 19:32:46 jim Exp $
"""
import re
from zope.documenttemplate.dt_string import String
from zope.documenttemplate.dt_util import ParseError, str
class DTMLRegExClass:
def search(self, text, start=0,
name_match=re.compile('[\0- ]*[a-zA-Z]+[\0- ]*').match,
start_search=re.compile('[<&]').search,
ent_name=re.compile('[-a-zA-Z0-9_.]+').match
):
while 1:
mo = start_search(text, start)
if mo is None:
return None
s = mo.start(0)
if text[s:s+6] == '<dtml-':
e = n = s+6
while 1:
e = text.find('>', e+1)
if e < 0:
return None
if len(text[n:e].split('"'))%2:
# check for even number of "s inside
break
en = 1
end = ''
elif text[s:s+7] == '</dtml-':
e=n=s+7
while 1:
e=text.find('>',e+1)
if e < 0:
return None
if len(text[n:e].split('"'))%2:
# check for even number of "s inside
break
en=1
end='/'
else:
if text[s:s+5] == '&dtml' and text[s+5] in '.-':
n=s+6
e=text.find(';', n)
if e >= 0:
args=text[n:e]
l=len(args)
mo = ent_name(args)
if mo is not None and mo.end(0)-mo.start(0) == l:
d=self.__dict__
if text[s+5] == '-':
d[1] = d['end'] = ''
d[2] = d['name'] = 'var'
d[0] = text[s:e+1]
d[3] = d['args'] = args + ' html_quote'
self._start = s
return self
else:
nn=args.find('-')
if nn >= 0 and nn < l-1:
d[1]=d['end']=''
d[2]=d['name']='var'
d[0]=text[s:e+1]
args=(args[nn+1:]+' '+
args[:nn].replace('.', ' '))
d[3]=d['args']=args
self._start = s
return self
start = s + 1
continue
break
mo=name_match(text,n)
if mo is None:
return None
l = mo.end(0) - mo.start(0)
a=n+l
name=text[n:a].strip()
args=text[a:e].strip()
d=self.__dict__
d[0]=text[s:e+en]
d[1]=d['end']=end
d[2]=d['name']=name
d[3]=d['args']=args
self._start = s
return self
def group(self, *args):
get=self.__dict__.get
if len(args)==1:
return get(args[0])
return tuple(map(get, args))
def start(self, *args):
return self._start
class HTML(String):
"""HTML Document Templates
HTML Document templates use HTML server-side-include syntax,
rather than Python format-string syntax. Here's a simple example:
<dtml-in results>
<dtml-var name>
</dtml-in>
HTML document templates quote HTML tags in source when the
template is converted to a string. This is handy when templates
are inserted into HTML editing forms.
"""
def tagre(self):
return DTMLRegExClass()
def parseTag(self, tagre, command=None, sargs=''):
"""Parse a tag using an already matched re
Return: tag, args, command, coname
where: tag is the tag,
args is the tag\'s argument string,
command is a corresponding command info structure if the
tag is a start tag, or None otherwise, and
coname is the name of a continue tag (e.g. else)
or None otherwise
"""
tag, end, name, args, =tagre.group(0, 'end', 'name', 'args')
args=args.strip()
if end:
if not command or name != command.name:
raise ParseError, ('unexpected end tag', tag)
return tag, args, None, None
if command and name in command.blockContinuations:
if name=='else' and args:
# Waaaaaah! Have to special case else because of
# old else start tag usage. Waaaaaaah!
l=len(args)
if not (args==sargs or
args==sargs[:l] and sargs[l:l+1] in ' \t\n'):
return tag, args, self.commands[name], None
return tag, args, None, name
try: return tag, args, self.commands[name], None
except KeyError:
raise ParseError, ('Unexpected tag', tag)
def SubTemplate(self, name):
return HTML('', __name__=name)
def varExtra(self,tagre):
return 's'
def quotedHTML(self,
text=None,
character_entities=(
(('&'), '&'),
(("<"), '<' ),
((">"), '>' ),
(('"'), '"'))): #"
if text is None: text=self.read_raw()
for re,name in character_entities:
if text.find(re) >= 0: text=name.join(text.split(re))
return text
errQuote__roles__=()
errQuote=quotedHTML
def __str__(self):
return self.quotedHTML()
=== Added File Zope3/src/zope/documenttemplate/dt_if.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Conditional insertion
Conditional insertion is performed using 'if' and 'else'
commands.
To include text when an object is true using the EPFS
format, use::
%(if name)[
text
%(if name)]
To include text when an object is true using the HTML
format, use::
<dtml-if name>
text
</dtml-if name>
where 'name' is the name bound to the object.
To include text when an object is false using the EPFS
format, use::
%(else name)[
text
%(else name)]
To include text when an object is false using the HTML
format, use::
<dtml-else name>
text
</dtml-else name>
Finally to include text when an object is true and to
include different text when the object is false using the
EPFS format, use::
%(if name)[
true text
%(if name)]
%(else name)[
false text
%(else name)]
and to include text when an object is true and to
include different text when the object is false using the
HTML format, use::
<dtml-if name>
true text
<dtml-else name>
false text
</dtml-if name>
Notes:
- if a variable is nor defined, it is considered to be false.
- A variable if only evaluated once in an 'if' tag. If the value
is used inside the tag, including in enclosed tags, the
variable is not reevaluated.
$Id: dt_if.py,v 1.1.2.1 2002/12/23 19:32:46 jim Exp $
"""
from zope.documenttemplate.dt_util import ParseError, parse_params, name_param, str
class If:
blockContinuations = 'else', 'elif'
name = 'if'
elses = None
expr = ''
def __init__(self, blocks):
tname, args, section = blocks[0]
args = parse_params(args, name='', expr='')
name,expr = name_param(args,'if',1)
self.__name__ = name
if expr is None:
cond = name
else:
cond = expr.eval
sections = [cond, section.blocks]
if blocks[-1][0] == 'else':
tname, args, section = blocks[-1]
del blocks[-1]
args = parse_params(args, name='')
if args:
ename,expr=name_param(args,'else',1)
if ename != name:
raise ParseError, ('name in else does not match if', 'in')
elses=section.blocks
else: elses = None
for tname, args, section in blocks[1:]:
if tname == 'else':
raise ParseError, (
'more than one else tag for a single if tag', 'in')
args = parse_params(args, name='', expr='')
name,expr = name_param(args, 'elif', 1)
if expr is None:
cond = name
else:
cond = expr.eval
sections.append(cond)
sections.append(section.blocks)
if elses is not None:
sections.append(elses)
self.simple_form = tuple(sections)
class Unless:
name = 'unless'
blockContinuations = ()
def __init__(self, blocks):
tname, args, section = blocks[0]
args=parse_params(args, name='', expr='')
name,expr=name_param(args, 'unless', 1)
if expr is None:
cond = name
else:
cond = expr.eval
self.simple_form = (cond, None, section.blocks)
class Else(Unless):
# The else tag is included for backward compatibility and is deprecated.
name = 'else'
=== Added File Zope3/src/zope/documenttemplate/dt_in.py === (685/785 lines abridged)
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Sequence insertion
A sequence may be inserted using an 'in' command. The 'in'
command specifies the name of a sequence object and text to
be inserted for each element in the sequence.
The EPFS syntax for the in command is::
%(in name)[
text
%(in name)]
The HTML syntax for the in command is::
<dtml-in name>
text
</dtml-in name>
See the example below that shows how 'if', 'else', and 'in' commands
may be combined to display a possibly empty list of objects.
The text included within an 'in' command will be refered to
as an 'in' block.
Synopsis
If the variable 'sequence' exists as a sequence, a simple case
of the 'in' tag is used as follows::
<dtml-in sequence>some markup</dtml-in>
A more complete case is used as follows::
<dtml-in sequence sort=age>
<dtml-var sequence-number>) <dtml-var age>
</dtml-in>
[-=- -=- -=- 685 lines omitted -=- -=- -=-]
akey = akey()
except:
pass
k.append(akey)
else: # One sort key.
try:
if mapping:
k = v[sort]
else:
k = getattr(v, sort)
except AttributeError, KeyError:
k = None
if not basic_type(type(k)):
try:
k = k()
except:
pass
s.append((k,client))
s.sort()
sequence = []
for k, client in s:
sequence.append(client)
return sequence
def reverse_sequence(self, sequence):
s = list(sequence)
s.reverse()
return s
basic_type = {StringType: 1, IntType: 1, FloatType: 1, TupleType: 1,
ListType: 1, NoneType: 1}.has_key
def int_param(params, md, name, default=0, st=StringType):
try:
v = params[name]
except:
v = default
if v:
try:
v = v.atoi()
except:
v = md[v]
if isinstance(v, st):
v = v.atoi()
return v
=== Added File Zope3/src/zope/documenttemplate/dt_insv.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Sequence variables support
$Id: dt_insv.py,v 1.1.2.1 2002/12/23 19:32:46 jim Exp $
"""
from math import sqrt
from types import IntType, TupleType
try:
import Missing
mv = Missing.Value
except: mv = None
class sequence_variables:
def __init__(self, items=None, query_string='', start_name_re=None):
self.items = items
self.query_string = query_string
self.start_name_re = start_name_re
self.data = data = {
'previous-sequence': 0,
'next-sequence': 0,
'sequence-start': 1,
'sequence-end': 0,
}
def __len__(self):
return 1
def number(self, index):
return index+1
def even(self, index):
return index%2 == 0
def odd(self, index):
return index%2
def letter(self, index):
return chr(ord('a') + index)
def Letter(self, index):
return chr(ord('A') + index)
def key(self,index):
return self.items[index][0]
def item(self,index, tt = TupleType):
i = self.items[index]
if isinstance(i, tt) and len(i)==2:
return i[1]
return i
def roman(self, index):
return self.Roman(index).lower()
def Roman(self,num):
# Force number to be an integer value
num = int(num) + 1
# Initialize roman as an empty string
roman = ''
while num >= 1000:
num = num - 1000
roman = '%sM' % roman
while num >= 500:
num = num - 500
roman = '%sD' % roman
while num >= 100:
num = num - 100
roman = '%sC' % roman
while num >= 50:
num = num - 50
roman = '%sL' % roman
while num >= 10:
num = num - 10
roman = '%sX' % roman
while num >= 5:
num = num - 5
roman = '%sV' % roman
while num < 5 and num >= 1:
num = num - 1
roman = '%sI' % roman
# Replaces special cases in Roman Numerals
roman = sub('DCCCC', 'CM', roman)
roman = sub('CCCC', 'CD', roman)
roman = sub('LXXXX', 'XC', roman)
roman = sub('XXXX', 'XL', roman)
roman = sub('VIIII', 'IX', roman)
roman = sub('IIII', 'IV', roman)
return roman
def value(self, index, name):
data = self.data
item = self.items[index]
if isinstance(item, TupleType) and len(item)==2:
item = item[1]
if data['mapping']:
return item[name]
return getattr(item, name)
def first(self, name, key=''):
data = self.data
if data['sequence-start']:
return 1
index = data['sequence-index']
return self.value(index, name) != self.value(index-1, name)
def last(self, name, key=''):
data = self.data
if data['sequence-end']:
return 1
index = data['sequence-index']
return self.value(index, name) != self.value(index+1, name)
def length(self, ignored):
l=self.data['sequence-length'] = len(self.items)
return l
def query(self, *ignored):
if self.start_name_re is None:
raise KeyError, 'sequence-query'
query_string = self.query_string
while query_string and query_string[:1] in '?&':
query_string = query_string[1:]
while query_string[-1:] == '&':
query_string = query_string[:-1]
if query_string:
query_string = '&%s&' % query_string
re = self.start_name_re
l = re.search_group(query_string, (0,))
if l:
v = l[1]
l = l[0]
query_string = (query_string[:l] +
query_string[l + len(v) - 1:])
query_string = '?' + query_string[1:]
else:
query_string = '?'
self.data['sequence-query'] = query_string
return query_string
statistic_names = (
'total', 'count', 'min', 'max', 'median', 'mean',
'variance', 'variance-n','standard-deviation', 'standard-deviation-n',
)
def statistics(self, name, key):
items = self.items
data = self.data
mapping = data['mapping']
count = sum = sumsq = 0
min = max = None
scount = smin = smax = None
values = []
svalues = []
for item in items:
try:
if mapping:
item = item[name]
else:
item = getattr(item, name)
try:
if item is mv:
item = None
if isinstance(item, IntType):
s = item * long(item)
else:
s = item * item
sum = sum + item
sumsq = sumsq + s
values.append(item)
if min is None:
min = max = item
else:
if item < min:
min = item
if item > max:
max = item
except:
if item is not None and item is not mv:
if smin is None:
smin = smax = item
else:
if item < smin:
smin = item
if item > smax:
smax = item
svalues.append(item)
except: pass
# Initialize all stats to empty strings:
for stat in self.statistic_names:
data['%s-%s' % (stat,name)] = ''
count = len(values)
try: # Numeric statistics
n = float(count)
mean = sum/n
sumsq = sumsq/n - mean*mean
data['mean-%s' % name] = mean
data['total-%s' % name] = sum
data['variance-n-%s' % name] = sumsq
data['standard-deviation-n-%s' % name] = sqrt(sumsq)
if count > 1:
sumsq = sumsq * n/(n-1)
data['variance-%s' % name] = sumsq
data['standard-deviation-%s' % name] = sqrt(sumsq)
else:
data['variance-%s' % name] = ''
data['standard-deviation-%s' % name] = ''
except:
if min is None: min, max, values = smin, smax, svalues
else:
if smin < min:
min = smin
if smax > max:
max = smax
values = values + svalues
count = len(values)
data['count-%s' % name] = count
# data['_values']=values
if min is not None:
data['min-%s' % name] = min
data['max-%s' % name] = max
values.sort()
if count == 1:
data['median-%s' % name] = min
else:
n=count+1
if n/2 * 2 == n:
data['median-%s' % name] = values[n/2 - 1]
else:
n = n/2
try:
data['median-%s' % name] = (values[n]+values[n-1])/2
except:
try:
data['median-%s' % name] = (
"between %s and %s" % (values[n], values[n-1]))
except: pass
return data[key]
def next_batches(self, suffix='batches', key=''):
if suffix != 'batches':
raise KeyError, key
data = self.data
sequence = self.items
try:
if not data['next-sequence']:
return ()
sz = data['sequence-step-size']
start = data['sequence-step-start']
end = data['sequence-step-end']
l = len(sequence)
orphan = data['sequence-step-orphan']
overlap = data['sequence-step-overlap']
except:
AttributeError, 'next-batches'
r = []
while end < l:
start, end, spam = opt(end+1-overlap, 0, sz, orphan, sequence)
v = sequence_variables(self.items,
self.query_string, self.start_name_re)
d = v.data
d['batch-start-index'] = start-1
d['batch-end-index'] = end-1
d['batch-size'] = end+1-start
d['mapping'] = data['mapping']
r.append(v)
data['next-batches'] = r
return r
def previous_batches(self, suffix='batches', key=''):
if suffix != 'batches':
raise KeyError, key
data = self.data
sequence = self.items
try:
if not data['previous-sequence']:
return ()
sz = data['sequence-step-size']
start = data['sequence-step-start']
end = data['sequence-step-end']
l = len(sequence)
orphan = data['sequence-step-orphan']
overlap = data['sequence-step-overlap']
except:
AttributeError, 'previous-batches'
r = []
while start > 1:
start, end, spam = opt(0, start-1+overlap, sz, orphan, sequence)
v = sequence_variables(self.items,
self.query_string, self.start_name_re)
d = v.data
d['batch-start-index'] = start-1
d['batch-end-index'] = end-1
d['batch-size'] = end+1-start
d['mapping'] = data['mapping']
r.append(v)
r.reverse()
data['previous-batches'] = r
return r
special_prefixes = {
'first': first,
'last': last,
'previous': previous_batches,
'next': next_batches,
# These two are for backward compatability with a missfeature:
'sequence-index': lambda self, suffix, key: self['sequence-'+suffix],
'sequence-index-is': lambda self, suffix, key: self['sequence-'+suffix],
}
for n in statistic_names:
special_prefixes[n] = statistics
def __getitem__(self,key,
special_prefixes=special_prefixes,
special_prefix=special_prefixes.has_key
):
data = self.data
if data.has_key(key):
return data[key]
l = key.rfind('-')
if l < 0:
raise KeyError, key
suffix = key[l+1:]
prefix = key[:l]
if hasattr(self, suffix):
try:
v = data[prefix+'-index']
except:
pass
else:
return getattr(self, suffix)(v)
if special_prefix(prefix):
return special_prefixes[prefix](self, suffix, key)
if prefix[-4:] == '-var':
prefix = prefix[:-4]
try:
return self.value(data[prefix+'-index'], suffix)
except:
pass
if key == 'sequence-query':
return self.query()
raise KeyError, key
def sub(s1, s2, src):
return s2.join(src.split(s1))
def opt(start, end, size, orphan, sequence):
if size < 1:
if start > 0 and end > 0 and end >= start:
size = end+1 - start
else: size = 7
if start > 0:
try:
sequence[start-1]
except:
start = len(sequence)
if end > 0:
if end < start:
end = start
else:
end = start + size-1
try:
sequence[end+orphan-1]
except:
end = len(sequence)
elif end > 0:
try:
sequence[end-1]
except:
end=len(sequence)
start = end+1 - size
if start - 1 < orphan:
start = 1
else:
start = 1
end = start + size-1
try:
sequence[end+orphan-1]
except:
end = len(sequence)
return start, end, size
=== Added File Zope3/src/zope/documenttemplate/dt_let.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""The Let tag was contributed to Zope by and is copyright, 1999
Phillip J. Eby. Permission has been granted to release the Let tag
under the Zope Public License.
Let name=value...
The 'let' tag is used to bind variables to values within a block.
The text enclosed in the let tag is rendered using information
from the given variables or expressions.
For example::
<dtml-let foofunc="foo()" my_bar=bar>
foo() = <dtml-var foofunc>,
bar = <dtml-var my_bar>
</dtml-let>
Notice that both 'name' and 'expr' style attributes may be used to
specify data. 'name' style attributes (e.g. my_bar=bar) will be
rendered as they are for var/with/in/etc. Quoted attributes will
be treated as Python expressions.
Variables are processed in sequence, so later assignments can
reference and/or overwrite the results of previous assignments,
as desired.
$Id: dt_let.py,v 1.1.2.1 2002/12/23 19:32:46 jim Exp $
"""
from zope.documenttemplate.dt_util import render_blocks, Eval, ParseError
from zope.documenttemplate.dt_util import str # Probably needed due to hysterical pickles.
from types import StringType
import re
class Let:
blockContinuations = ()
name = 'let'
def __init__(self, blocks):
tname, args, section = blocks[0]
self.__name__ = args
self.section = section.blocks
self.args = args = parse_let_params(args)
for i in range(len(args)):
name,expr = args[i]
if expr[:1] == '"' and expr[-1:] == '"' and len(expr) > 1:
# expr shorthand
expr = expr[1:-1]
try:
args[i] = name, Eval(expr).eval
except SyntaxError, v:
m,(huh,l,c,src) = v
raise ParseError, (
'<strong>Expression (Python) Syntax error</strong>:'
'\n<pre>\n%s\n</pre>\n' % v[0],
'let')
def render(self, md):
d = {}
md._push(d)
try:
for name,expr in self.args:
if isinstance(expr, StringType):
d[name] = md[expr]
else:
d[name] = expr(md)
return render_blocks(self.section, md)
finally:
md._pop(1)
__call__ = render
def parse_let_params(text,
result=None,
tag='let',
parmre=re.compile('([\000- ]*([^\000- ="]+)=([^\000- ="]+))'),
qparmre=re.compile('([\000- ]*([^\000- ="]+)="([^"]*)")'),
**parms):
result = result or []
mo = parmre.match(text)
mo1 = qparmre.match(text)
if mo is not None:
name = mo.group(2)
value = mo.group(3)
l = len(mo.group(1))
elif mo1 is not None:
name = mo1.group(2)
value = '"%s"' % mo1.group(3)
l = len(mo1.group(1))
else:
if not text or not text.strip():
return result
raise ParseError, ('invalid parameter: "%s"' % text, tag)
result.append((name,value))
text = text[l:].strip()
if text:
return apply(parse_let_params, (text, result,tag), parms)
else:
return result
=== Added File Zope3/src/zope/documenttemplate/dt_raise.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
'''Raising exceptions
Errors can be raised from DTML using the 'raise' tag.
For example::
<dtml-if expr="condition_that_tests_input">
<dtml-raise type="Input Error">
The value you entered is not valid
</dtml-raise>
</dtml-if>
$Id: dt_raise.py,v 1.1.2.1 2002/12/23 19:32:46 jim Exp $
'''
from zope.documenttemplate.dt_util import parse_params, name_param, render_blocks, str
class Raise:
blockContinuations = ()
name = 'raise'
expr = ''
def __init__(self, blocks):
tname, args, section = blocks[0]
self.section=section.blocks
args=parse_params(args, type='', expr='')
self.__name__, self.expr = name_param(args, 'raise', 1, attr='type')
def render(self, md):
expr = self.expr
if expr is None:
t = self.__name__
if t[-5:] == 'Error' and __builtins__.has_key(t):
t = __builtins__[t]
else:
try:
t = expr.eval(md)
except:
t = 'Invalid Error Type Expression'
try:
v = render_blocks(self.section,md)
except:
v = 'Invalid Error Value'
raise t, v
__call__ = render
=== Added File Zope3/src/zope/documenttemplate/dt_return.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id: dt_return.py,v 1.1.2.1 2002/12/23 19:32:46 jim Exp $
"""
from zope.documenttemplate.dt_util import parse_params, name_param, html_quote, str
class ReturnTag:
name = 'return'
expr = None
def __init__(self, args):
args = parse_params(args, name='', expr='')
name, expr = name_param(args,'var',1)
self.__name__, self.expr = name, expr
def render(self, md):
name = self.__name__
val = self.expr
if val is None:
val = md[name]
else:
val = val.eval(md)
raise DTReturn(val)
__call__ = render
class DTReturn:
def __init__(self, v):
self.v = v
=== Added File Zope3/src/zope/documenttemplate/dt_string.py === (405/505 lines abridged)
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id: dt_string.py,v 1.1.2.1 2002/12/23 19:32:46 jim Exp $
"""
import re, thread
from zope.documenttemplate.dt_util import ParseError, InstanceDict, TemplateDict, render_blocks, str
from zope.documenttemplate.dt_var import Var, Call, Comment
from zope.documenttemplate.dt_return import ReturnTag, DTReturn
from types import TupleType
_marker = [] # Create a new marker object.
class String:
"""Document templates defined from strings.
Document template strings use an extended form of python string
formatting. To insert a named value, simply include text of the
form: '%(name)x', where 'name' is the name of the value and 'x' is
a format specification, such as '12.2d'.
To intrduce a block such as an 'if' or an 'in' or a block continuation,
such as an 'else', use '[' as the format specification. To
terminate a block, ise ']' as the format specification, as in::
%(in results)[
%(name)s
%(in results)]
"""
# Document Templates masquerade as functions:
class func_code:
pass
func_code = func_code()
func_code.co_varnames = 'self', 'REQUEST'
[-=- -=- -=- 405 lines omitted -=- -=- -=-]
if level > 200:
raise SystemError, ('infinite recursion in document template')
md.level = level+1
if client is not None:
if isinstance(client, TupleType):
# if client is a tuple, it represents a "path" of clients
# which should be pushed onto the md in order.
for ob in client:
push(InstanceDict(ob, md)) # Circ. Ref. 8-|
pushed += 1
else:
# otherwise its just a normal client object.
push(InstanceDict(client, md)) # Circ. Ref. 8-|
pushed += 1
if self._vars:
push(self._vars)
pushed += 1
if kw:
push(kw)
pushed += 1
try:
try:
result = render_blocks(self._v_blocks, md)
except DTReturn, v:
result = v.v
return result
finally:
if pushed:
md._pop(pushed) # Get rid of circular reference!
md.level=level # Restore previous level
validate=None
def __str__(self):
return self.read()
def __getstate__(self, _special=('_v_', '_p_')):
# Waaa, we need _v_ behavior but we may not subclass Persistent
d={}
for k, v in self.__dict__.items():
if k[:3] in _special: continue
d[k] = v
return d
=== Added File Zope3/src/zope/documenttemplate/dt_try.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id: dt_try.py,v 1.1.2.1 2002/12/23 19:32:46 jim Exp $
"""
import sys, traceback
from StringIO import StringIO
from zope.documenttemplate.dt_util import ParseError, parse_params, render_blocks
from zope.documenttemplate.dt_util import namespace, InstanceDict
from zope.documenttemplate.dt_return import DTReturn
from types import StringType
class Try:
"""Zope DTML Exception handling
usage:
<dtml-try>
<dtml-except SomeError AnotherError>
<dtml-except YetAnotherError>
<dtml-except>
<dtml-else>
</dtml-try>
or:
<dtml-try>
<dtml-finally>
</dtml-try>
The DTML try tag functions quite like Python's try command.
The contents of the try tag are rendered. If an exception is raised,
then control switches to the except blocks. The first except block to
match the type of the error raised is rendered. If an except block has
no name then it matches all raised errors.
The try tag understands class-based exceptions, as well as string-based
exceptions. Note: the 'raise' tag raises string-based exceptions.
Inside the except blocks information about the error is available via
three variables.
'error_type' -- This variable is the name of the exception caught.
'error_value' -- This is the caught exception's value.
'error_tb' -- This is a traceback for the caught exception.
The optional else block is rendered when no exception occurs in the
try block. Exceptions in the else block are not handled by the preceding
except blocks.
The try..finally form specifies a `cleanup` block, to be rendered even
when an exception occurs. Note that any rendered result is discarded if
an exception occurs in either the try or finally blocks. The finally block
is only of any use if you need to clean up something that will not be
cleaned up by the transaction abort code.
The finally block will always be called, wether there was an exception in
the try block or not, or wether or not you used a return tag in the try
block. Note that any output of the finally block is discarded if you use a
return tag in the try block.
If an exception occurs in the try block, and an exception occurs in the
finally block, or you use the return tag in that block, any information
about that first exception is lost. No information about the first
exception is available in the finally block. Also, if you use a return tag
in the try block, and an exception occurs in the finally block or you use
a return tag there as well, the result returned in the try block will be
lost.
Original version by Jordan B. Baker.
Try..finally and try..else implementation by Martijn Pieters.
"""
name = 'try'
blockContinuations = 'except', 'else', 'finally'
finallyBlock = None
elseBlock = None
def __init__(self, blocks):
tname, args, section = blocks[0]
self.args = parse_params(args)
self.section = section.blocks
# Find out if this is a try..finally type
if len(blocks) == 2 and blocks[1][0] == 'finally':
self.finallyBlock = blocks[1][2].blocks
# This is a try [except]* [else] block.
else:
# store handlers as tuples (name,block)
self.handlers = []
defaultHandlerFound = 0
for tname, nargs, nsection in blocks[1:]:
if tname == 'else':
if not self.elseBlock is None:
raise ParseError, (
'No more than one else block is allowed',
self.name)
self.elseBlock = nsection.blocks
elif tname == 'finally':
raise ParseError, (
'A try..finally combination cannot contain '
'any other else, except or finally blocks',
self.name)
else:
if not self.elseBlock is None:
raise ParseError, (
'The else block should be the last block '
'in a try tag', self.name)
for errname in nargs.split():
self.handlers.append((errname, nsection.blocks))
if nargs.strip() == '':
if defaultHandlerFound:
raise ParseError, (
'Only one default exception handler '
'is allowed', self.name)
else:
defaultHandlerFound = 1
self.handlers.append(('', nsection.blocks))
def render(self, md):
if (self.finallyBlock is None):
return self.render_try_except(md)
else:
return self.render_try_finally(md)
def render_try_except(self, md):
result = ''
# first we try to render the first block
try:
result = render_blocks(self.section, md)
except DTReturn:
raise
except:
# but an error occurs.. save the info.
t, v = sys.exc_info()[:2]
if isinstance(t, StringType):
errname = t
else:
errname = t.__name__
handler = self.find_handler(t)
if handler is None:
# we didn't find a handler, so reraise the error
raise
# found the handler block, now render it
try:
f = StringIO()
traceback.print_exc(100,f)
error_tb = f.getvalue()
ns = namespace(md, error_type=errname, error_value=v,
error_tb=error_tb)[0]
md._push(InstanceDict(ns,md))
return render_blocks(handler, md)
finally:
md._pop(1)
else:
# No errors have occured, render the optional else block
if (self.elseBlock is None):
return result
else:
return result + render_blocks(self.elseBlock, md)
def render_try_finally(self, md):
result = ''
# first try to render the first block
try:
result = render_blocks(self.section, md)
# Then handle finally block
finally:
result = result + render_blocks(self.finallyBlock, md)
return result
def find_handler(self,exception):
"recursively search for a handler for a given exception"
if isinstance(exception, StringType):
for e,h in self.handlers:
if exception==e or e=='':
return h
else:
return None
for e,h in self.handlers:
if e==exception.__name__ or e=='' or self.match_base(exception,e):
return h
return None
def match_base(self,exception,name):
for base in exception.__bases__:
if base.__name__ == name or self.match_base(base, name):
return 1
return None
__call__ = render
=== Added File Zope3/src/zope/documenttemplate/dt_util.py === (408/508 lines abridged)
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id: dt_util.py,v 1.1.2.1 2002/12/23 19:32:46 jim Exp $
"""
import re, math
import whrandom
from __builtin__ import str # XXX needed for pickling (legacy)
from types import ListType, StringType, TupleType
from zope.documenttemplate.pdocumenttemplate import InstanceDict, TemplateDict, render_blocks
ParseError='Document Template Parse Error'
ValidationError='Unauthorized'
def html_quote(v, name='(Unknown name)', md={},
character_entities=(
(('&'), '&'),
(('<'), '<' ),
(('>'), '>' ),
(('"'), '"'))): #"
text = str(v)
for re, name in character_entities:
text = text.replace(re, name)
return text
def int_param(params, md, name, default=0):
try:
v = params[name]
except:
v = default
if v:
try:
v = v.atoi()
[-=- -=- -=- 408 lines omitted -=- -=- -=-]
name = mo_p.group(2).lower()
value = mo_p.group(3)
l = len(mo_p.group(1))
elif mo_q:
name = mo_q.group(2).lower()
value = mo_q.group(3)
l = len(mo_q.group(1))
elif mo_unp:
name = mo_unp.group(2)
l = len(mo_unp.group(1))
if result:
if parms.has_key(name):
if parms[name] is None: raise ParseError, (
'Attribute %s requires a value' % name, tag)
result[name] = parms[name]
else: raise ParseError, (
'Invalid attribute name, "%s"' % name, tag)
else:
result[''] = name
return apply(parse_params, (text[l:],result), parms)
elif mo_unq:
name = mo_unq.group(2)
l = len(mo_unq.group(1))
if result:
raise ParseError, ('Invalid attribute name, "%s"' % name, tag)
else:
result[''] = name
return apply(parse_params, (text[l:], result), parms)
else:
if not text or not text.strip():
return result
raise ParseError, ('invalid parameter: "%s"' % text, tag)
if not parms.has_key(name):
raise ParseError, ('Invalid attribute name, "%s"' % name, tag)
if result.has_key(name):
p = parms[name]
if type(p) is not ListType or p:
raise ParseError, (
'Duplicate values for attribute "%s"' % name, tag)
result[name] = value
text = text[l:].strip()
if text:
return apply(parse_params, (text,result), parms)
else:
return result
=== Added File Zope3/src/zope/documenttemplate/dt_var.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Variable insertion parameters
When inserting variables, parameters may be specified to
control how the data will be formatted. In HTML source, the
'fmt' parameter is used to specify a C-style or custom format
to be used when inserting an object. In EPFS source, the 'fmt'
parameter is only used for custom formats, a C-style format is
specified after the closing parenthesis.
Custom formats
A custom format is used when outputing user-defined
objects. The value of a custom format is a method name to
be invoked on the object being inserted. The method should
return an object that, when converted to a string, yields
the desired text. For example, the HTML source::
<!--#var date fmt=DayOfWeek-->
Inserts the result of calling the method 'DayOfWeek' of the
object bound to the variable 'date', with no arguments.
In addition to object methods, serveral additional custom
formats are available:
'whole-dollars' -- Show a numeric value with a dollar symbol.
'dollars-and-cents' -- Show a numeric value with a dollar
symbol and two decimal places.
'collection-length' -- Get the length of a collection of objects.
Note that when using the EPFS source format, both a
C-style and a custom format may be provided. In this case,
the C-Style format is applied to the result of calling
the custom formatting method.
Null values and missing variables
In some applications, and especially in database applications,
data variables may alternate between "good" and "null" or
"missing" values. A format that is used for good values may be
inappropriate for null values. For this reason, the 'null'
parameter can be used to specify text to be used for null
values. Null values are defined as values that:
- Cannot be formatted with the specified format, and
- Are either the special Python value 'None' or
are false and yield an empty string when converted to
a string.
For example, when showing a monitary value retrieved from a
database that is either a number or a missing value, the
following variable insertion might be used::
<dtml-var cost fmt="$%.2d" null=\'n/a\'>
Missing values are providing for variables which are not
present in the name space, rather than raising an NameError,
you could do this:
<dtml-var cost missing=0>
and in this case, if cost was missing, it would be set to 0.
In the case where you want to deal with both at the same time,
you can use 'default':
<dtml-var description default=''>
In this case, it would use '' if the value was null or if the
variable was missing.
String manipulation
A number of special attributes are provided to transform the
value after formatting has been applied. These parameters
are supplied without arguments.
'lower' -- cause all upper-case letters to be converted to lower case.
'upper' -- cause all upper-case letters to be converted to lower case.
'capitalize' -- cause the first character of the inserted value
to be converted to upper case.
'spacify' -- cause underscores in the inserted value to be
converted to spaces.
'thousands_commas' -- cause commas to be inserted every three
digits to the left of a decimal point in values containing
numbers. For example, the value, "12000 widgets" becomes
"12,000 widgets".
'html_quote' -- convert characters that have special meaning
in HTML to HTML character entities.
'url_quote' -- convert characters that have special meaning
in URLS to HTML character entities using decimal values.
'url_quote_plus' -- like url_quote but also replace blank
space characters with '+'. This is needed for building
query strings in some cases.
'sql_quote' -- Convert single quotes to pairs of single
quotes. This is needed to safely include values in
Standard Query Language (SQL) strings.
'newline_to_br' -- Convert newlines and carriage-return and
newline combinations to break tags.
'url' -- Get the absolute URL of the object by calling it\'s
'absolute_url' method, if it has one.
Truncation
The attributes 'size' and 'etc' can be used to truncate long
strings. If the 'size' attribute is specified, the string to
be inserted is truncated at the given length. If a space
occurs in the second half of the truncated string, then the
string is further truncated to the right-most space. After
truncation, the value given for the 'etc' attribute is added to
the string. If the 'etc' attribute is not provided, then '...'
is used. For example, if the value of spam is
'"blah blah blah blah"', then the tag
'<!--#var spam size=10-->' inserts '"blah blah ..."'.
Evaluating expressions without rendering results
A 'call' tag is provided for evaluating named objects or expressions
without rendering the result.
$Id: dt_var.py,v 1.1.2.1 2002/12/23 19:32:46 jim Exp $
"""
from zope.documenttemplate.dt_util import parse_params, name_param, html_quote, str
import re, sys
from urllib import quote, quote_plus
class Var:
name = 'var'
expr = None
def __init__(self, args, fmt='s'):
if args[:4] == 'var ':
args = args[4:]
args = parse_params(args, name='', lower=1, upper=1, expr='',
capitalize=1, spacify=1, null='', fmt='s',
size=0, etc='...', thousands_commas=1,
html_quote=1, url_quote=1, sql_quote=1,
url_quote_plus=1, missing='',
newline_to_br=1, url=1)
self.args = args
self.modifiers = tuple(
map(lambda t: t[1],
filter(lambda m, args=args, used=args.has_key:
used(m[0]) and args[m[0]],
modifiers)))
name, expr = name_param(args, 'var', 1)
self.__name__, self.expr = name, expr
self.fmt = fmt
if len(args) == 1 and fmt == 's':
if expr is None:
expr = name
else:
expr = expr.eval
self.simple_form = expr,
def render(self, md):
args = self.args
have_arg = args.has_key
name = self.__name__
val = self.expr
if val is None:
if md.has_key(name):
if have_arg('url'):
val = md.getitem(name,0)
val = val.absolute_url()
else:
val = md[name]
else:
if have_arg('missing'):
return args['missing']
else:
raise KeyError, name
else:
val = val.eval(md)
if have_arg('url'):
val = val.absolute_url()
__traceback_info__ = name, val, args
if have_arg('null') and not val and val != 0:
# check for null (false but not zero, including None, [], '')
return args['null']
# handle special formats defined using fmt= first
if have_arg('fmt'):
fmt=args['fmt']
if have_arg('null') and not val and val != 0:
try:
if hasattr(val, fmt):
val = getattr(val,fmt)()
elif special_formats.has_key(fmt):
val = special_formats[fmt](val, name, md)
elif fmt == '':
val = ''
else:
val = fmt % val
except:
t, v = sys.exc_info()[:2]
if val is None or not str(val):
return args['null']
raise t, v
else:
# We duplicate the code here to avoid exception handler
# which tends to screw up stack or leak
if hasattr(val, fmt):
val = getattr(val,fmt)()
elif special_formats.has_key(fmt):
val = special_formats[fmt](val, name, md)
elif fmt == '':
val = ''
else:
val = fmt % val
# finally, pump it through the actual string format...
fmt=self.fmt
if fmt == 's':
val = str(val)
else:
val = ('%'+self.fmt) % (val,)
# next, look for upper, lower, etc
for f in self.modifiers:
val = f(val)
if have_arg('size'):
size = args['size']
try:
size = int(size)
except:
raise 'Document Error',(
'''a <code>size</code> attribute was used in a <code>var</code>
tag with a non-integer value.''')
if len(val) > size:
val = val[:size]
l = val.rfind(' ')
if l > size/2:
val = val[:l+1]
if have_arg('etc'):
l = args['etc']
else:
l = '...'
val += l
return val
__call__ = render
class Call:
name = 'call'
expr = None
def __init__(self, args):
args = parse_params(args, name='', expr='')
name, expr = name_param(args,'call',1)
if expr is None:
expr = name
else:
expr = expr.eval
self.simple_form = expr, None
def url_quote(v, name='(Unknown name)', md={}):
return quote(str(v))
def url_quote_plus(v, name='(Unknown name)', md={}):
return quote_plus(str(v))
def newline_to_br(v, name='(Unknown name)', md={}):
v = str(v)
if v.find('\r') >= 0:
v = ''.join(v.split('\r'))
if v.find('\n') >= 0:
v = '<br>\n'.join(v.split('\n'))
return v
def whole_dollars(v, name='(Unknown name)', md={}):
try:
return "$%d" % v
except:
return ''
def dollars_and_cents(v, name='(Unknown name)', md={}):
try:
return "$%.2f" % v
except:
return ''
def thousands_commas(v, name='(Unknown name)', md={},
thou=re.compile(
r"([0-9])([0-9][0-9][0-9]([,.]|$))").search):
v = str(v)
vl = v.split('.')
if not vl:
return v
v = vl[0]
del vl[0]
if vl:
s = '.' + '.'.join(vl)
else:
s = ''
mo = thou(v)
while mo is not None:
l = mo.start(0)
v = v[:l+1] + ',' + v[l+1:]
mo = thou(v)
return v+s
def whole_dollars_with_commas(v, name='(Unknown name)', md={}):
try:
v = "$%d" % v
except:
v = ''
return thousands_commas(v)
def dollars_and_cents_with_commas(v, name='(Unknown name)', md={}):
try:
v = "$%.2f" % v
except:
v = ''
return thousands_commas(v)
def len_format(v, name='(Unknown name)', md={}):
return str(len(v))
def len_comma(v, name='(Unknown name)', md={}):
return thousands_commas(str(len(v)))
StructuredText=None
def structured_text(v, name='(Unknown name)', md={}):
global StructuredText
if StructuredText is None:
import StructuredText
return str(StructuredText.html_with_references(str(v), 3))
def sql_quote(v, name='(Unknown name)', md={}):
"""Quote single quotes in a string by doubling them.
This is needed to securely insert values into sql
string literals in templates that generate sql.
"""
if v.find("'") >= 0:
return "''".join(v.split("'"))
return v
special_formats={
'whole-dollars': whole_dollars,
'dollars-and-cents': dollars_and_cents,
'collection-length': len_format,
# XXX: Gone for now
# 'structured-text': structured_text,
# The rest are depricated:
'sql-quote': sql_quote,
'html-quote': html_quote,
'url-quote': url_quote,
'url-quote-plus': url_quote_plus,
'multi-line': newline_to_br,
'comma-numeric': thousands_commas,
'dollars-with-commas': whole_dollars_with_commas,
'dollars-and-cents-with-commas': dollars_and_cents_with_commas,
}
def spacify(val):
if val.find('_') >= 0:
val = ' '.join(val.split('_'))
return val
def lower(val):
return val.lower()
def upper(val):
return val.upper()
def capitalize(val):
return val.capitalize()
modifiers = (html_quote, url_quote, url_quote_plus, newline_to_br,
lower, upper, capitalize, spacify,
thousands_commas, sql_quote)
modifiers = map(lambda f: (f.__name__, f), modifiers)
class Comment:
'''Comments
The 'comment' tag can be used to simply include comments
in DTML source.
For example::
<dtml-comment>
This text is not rendered.
</dtml-comment>
'''
name = 'comment'
blockContinuations = ()
def __init__(self, args, fmt=''):
pass
def render(self, md):
return ''
__call__=render
=== Added File Zope3/src/zope/documenttemplate/dt_with.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Nested namespace access
The 'with' tag is used to introduce nested namespaces.
The text enclosed in the with tag is rendered using information
from the given variable or expression.
For example, if the variable 'person' is bound to an object that
has attributes 'name' and 'age', then a 'with' tag like the
following can be used to access these attributes::
<dtml-with person>
<dtml-var name>,
<dtml-var age>
</dtml-with>
Eather a 'name' or an 'expr' attribute may be used to specify data.
A 'mapping' attribute may be used to indicate that the given data
should be treated as mapping object, rather than as an object with
named attributes.
$Id: dt_with.py,v 1.1.2.1 2002/12/23 19:32:46 jim Exp $
"""
from zope.documenttemplate.dt_util import parse_params, name_param, InstanceDict, render_blocks, str
from zope.documenttemplate.dt_util import TemplateDict
from types import StringType, TupleType
class With:
blockContinuations = ()
name = 'with'
mapping = None
only = 0
def __init__(self, blocks):
tname, args, section = blocks[0]
args = parse_params(args, name='', expr='', mapping=1, only=1)
name, expr = name_param(args, 'with', 1)
if expr is None:
expr = name
else:
expr = expr.eval
self.__name__, self.expr = name, expr
self.section=section.blocks
if args.has_key('mapping') and args['mapping']:
self.mapping = 1
if args.has_key('only') and args['only']:
self.only = 1
def render(self, md):
expr = self.expr
if isinstance(expr, StringType):
v = md[expr]
else:
v = expr(md)
if not self.mapping:
if isinstance(v, TupleType) and len(v) == 1:
v = v[0]
v = InstanceDict(v, md)
if self.only:
_md = md
md = TemplateDict()
if hasattr(_md, 'validate'):
md.validate = _md.validate
md._push(v)
try:
return render_blocks(self.section, md)
finally:
md._pop(1)
__call__ = render
=== Added File Zope3/src/zope/documenttemplate/pdocumenttemplate.py ===
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Python implementations of document template some features
$Id: pdocumenttemplate.py,v 1.1.2.1 2002/12/23 19:32:46 jim Exp $
"""
import sys
from types import StringTypes, TupleType, ClassType
ClassTypes = [ClassType]
def safe_callable(ob):
# Works with ExtensionClasses and Acquisition.
if hasattr(ob, '__class__'):
if hasattr(ob, '__call__'):
return 1
else:
return type(ob) in ClassTypes
else:
return callable(ob)
class InstanceDict:
def __init__(self, o, namespace):
self.self = o
self.cache = {}
self.namespace = namespace
def has_key(self,key):
return hasattr(self.self,key)
def keys(self):
return self.self.__dict__.keys()
def __repr__(self):
return 'InstanceDict(%s)' % str(self.self)
def __getitem__(self,key):
cache=self.cache
if cache.has_key(key):
return cache[key]
inst = self.self
if key[:1] == '_':
if key != '__str__':
raise KeyError, key # Don't divuldge private data
else:
return str(inst)
try:
r = getattr(inst, key)
except AttributeError:
raise KeyError, key
self.cache[key] = r
return r
def __len__(self):
return 1
class MultiMapping:
def __init__(self):
self.dicts = []
def __getitem__(self, key):
for d in self.dicts:
try:
return d[key]
except (KeyError, AttributeError):
pass
raise KeyError, key
def push(self,d):
self.dicts.insert(0, d)
def pop(self, n=1):
r = self.dicts[-1]
del self.dicts[:n]
return r
def keys(self):
kz = []
for d in self.dicts:
kz = kz + d.keys()
return kz
class DictInstance:
def __init__(self, mapping):
self.__d = mapping
def __getattr__(self, name):
try:
return self.__d[name]
except KeyError:
raise AttributeError, name
class TemplateDict:
level = 0
def _pop(self, n=1):
return self.dicts.pop(n)
def _push(self, d):
return self.dicts.push(d)
def __init__(self):
m = self.dicts = MultiMapping()
self._pop = m.pop
self._push = m.push
try:
self.keys = m.keys
except:
pass
def __getitem__(self,key,call=1):
v = self.dicts[key]
if call:
if hasattr(v, '__render_with_namespace__'):
return v.__render_with_namespace__(self)
vbase = getattr(v, 'aq_base', v)
if safe_callable(vbase):
v = v()
return v
def __len__(self):
total = 0
for d in self.dicts.dicts:
total += len(d)
return total
def has_key(self,key):
try:
v=self.dicts[key]
except KeyError:
return 0
return 1
getitem = __getitem__
def __call__(self, *args, **kw):
if args:
if len(args) == 1 and not kw:
m=args[0]
else:
m = self.__class__()
for a in args:
m._push(a)
if kw:
m._push(kw)
else:
m=kw
return (DictInstance(m),)
def render_blocks(blocks, md):
rendered = []
append = rendered.append
for section in blocks:
if type(section) is TupleType:
l = len(section)
if l == 1:
# Simple var
section = section[0]
if isinstance(section, StringTypes):
section = md[section]
else:
section = section(md)
section = str(section)
else:
# if
cache = {}
md._push(cache)
try:
i = 0
m = l-1
while i < m:
cond = section[i]
if isinstance(cond, StringTypes):
n = cond
try:
cond = md[cond]
cache[n] = cond
except KeyError, v:
v = v[0]
if n != v:
raise KeyError, v, sys.exc_traceback
cond=None
else:
cond = cond(md)
if cond:
section = section[i+1]
if section:
section = render_blocks(section,md)
else: section=''
m = 0
break
i += 2
if m:
if i == m:
section = render_blocks(section[i],md)
else:
section = ''
finally: md._pop()
elif not isinstance(section, StringTypes):
section = section(md)
if section:
rendered.append(section)
l = len(rendered)
if l == 0:
return ''
elif l == 1:
return rendered[0]
return ''.join(rendered)
return rendered