##############################################################################
#
# 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
#
##############################################################################
__doc__='''Python implementations of document template some features
$Id: pDocumentTemplate.py,v 1.36 2002/08/14 22:29:53 mj Exp $'''
__version__='$Revision: 1.36 $'[11:-2]
import sys, types
ClassTypes = [types.ClassType]
try:
from ExtensionClass import Base
except ImportError:
pass
else:
class c(Base): pass
ClassTypes.append(c.__class__)
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)
StringType=type('')
UnicodeType=type(u'')
TupleType=type(())
class InstanceDict:
guarded_getattr=None
def __init__(self,o,namespace,guarded_getattr=None):
self.self=o
self.cache={}
self.namespace=namespace
if guarded_getattr is None:
self.guarded_getattr = namespace.guarded_getattr
else: self.guarded_getattr = guarded_getattr
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)
get = self.guarded_getattr
if get is None:
get = getattr
try: r = get(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):
if getattr(vbase, 'isDocTemp', 0):
v = v(None, self)
else:
v = v()
return v
def __len__(self):
total = 0
for d in self.dicts.dicts:
total = 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 type(section) is StringType: section=md[section]
else: section=section(md)
section=ustr(section)
else:
# if
cache={}
md._push(cache)
try:
i=0
m=l-1
while i < m:
cond=section[i]
if type(cond) is StringType:
n=cond
try:
cond=md[cond]
cache[n]=cond
except KeyError, v:
v=str(v)
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=i+2
if m:
if i==m: section=render_blocks(section[i],md)
else: section=''
finally: md._pop()
elif type(section) is not StringType and type(section) is not UnicodeType:
section=section(md)
if section: rendered.append(section)
l=len(rendered)
if l==0: return ''
elif l==1: return rendered[0]
return join_unicode(rendered)
def join_unicode(rendered):
"""join a list of plain strings into a single plain string,
a list of unicode strings into a single unicode strings,
or a list containing a mix into a single unicode string with
the plain strings converted from latin-1
"""
try:
return ''.join(rendered)
except UnicodeError:
# A mix of unicode string and non-ascii plain strings.
# Fix up the list, treating normal strings as latin-1
rendered = list(rendered)
for i in range(len(rendered)):
if type(rendered[i]) is StringType:
rendered[i] = unicode(rendered[i],'latin-1')
return u''.join(rendered)
|