1
# Copyright (c) 2004 Divmod.
2
# See LICENSE for details.
4
from __future__ import generators
8
from zope.interface import declarations, interface
10
import twisted.python.components as tpc
12
from nevow import inevow
13
from nevow import tags
14
from nevow import util
15
from nevow.inevow import ISerializable
19
# If you're about to import something from this module then you probably want
20
# to get it from nevow.flat instead. The idea is that flat's __init__.py may
21
# get smarter about the version of serialize/flatten/etc that is used,
22
# depending on what else is available. For instance, non-Twisted versions of
23
# these function may be imported into nevow.flat if Twisted is not installed.
26
def registerFlattener(flattener, forType):
27
"""Register a function, 'flattener', which will be invoked when an object of type 'forType'
28
is encountered in the stan dom. This function should return or yield strings, or objects
29
for which there is also a flattener registered.
31
flattener should take (original, ctx) where original is the object to flatten.
33
if type(flattener) is str or type(forType) is str:
34
assert type(flattener) is str and type(forType) is str, "Must pass both strings or no strings to registerFlattener"
35
flattener = util._namedAnyWithBuiltinTranslation(flattener)
36
forType = util._namedAnyWithBuiltinTranslation(forType)
38
if not isinstance(forType, interface.InterfaceClass):
39
forType = declarations.implementedBy(forType)
41
tpc.globalRegistry.register([forType], ISerializable, 'nevow.flat', flattener)
43
def getFlattener(original):
44
"""Get a flattener function with signature (ctx, original) for the object original.
46
return tpc.globalRegistry.lookup1(declarations.providedBy(original), ISerializable, 'nevow.flat')
48
def getSerializer(obj):
49
warnings.warn('getSerializer is deprecated; It has been renamed getFlattener.', stacklevel=2)
50
return getFlattener(obj)
53
def partialflatten(context, obj):
54
"""Run a flattener on the object 'obj' in the context 'context'.
56
The return results from this function will not necessarily be a string, but will probably
57
need further processing.
59
flattener = getFlattener(obj)
60
if flattener is not None:
61
return flattener(obj, context)
63
raise NotImplementedError(
64
'There is no flattener function registered for object %r of type %s.' %
68
def serialize(obj, context):
69
#warnings.warn('serialize is deprecated; it has been renamed partialflatten.', stacklevel=2)
70
return partialflatten(context, obj)
73
def iterflatten(stan, ctx, writer, shouldYieldItem=None):
74
"""This is the main meat of the nevow renderer. End-user programmers should
75
instead use either flatten or precompile.
77
# 'rest' is a list of generators.
78
# initialize as one-element list of a one-element generator of
79
rest = [ iter([partialflatten(ctx, stan)]) ]
84
if isinstance(item, str):
86
elif isinstance(item, unicode):
87
straccum.append(item.encode('utf8'))
88
elif isinstance(item, (list, types.GeneratorType)):
89
# stop iterating this generator and put it back on the stack
90
# and start iterating the new item instead.
92
rest.append(iter(item))
96
writer(tags.raw(''.join(straccum)))
98
if shouldYieldItem is not None and shouldYieldItem(item):
100
yield item, replacement.append
102
rest.append(iter([replacement]))
106
## We're precompiling and this is an item which can't be calculated until render time
107
## add it to the list in 'precompile'
111
rest.append(iter([partialflatten(ctx, item)]))
115
writer(tags.raw(''.join(straccum)))
118
def flatten(stan, ctx=None):
119
"""Given the stan and the optional context, return a string containing the
120
representation of the tree in the given context.
123
from nevow.context import RequestContext, PageContext
124
from nevow.testutil import FakeRequest
125
ctx = PageContext(tag=None, parent=RequestContext(tag=FakeRequest()))
126
ctx.remember(None, inevow.IData)
128
list(iterflatten(stan, ctx, result.append))
129
return tags.raw(''.join(result))
132
def precompile(stan, ctx=None):
133
"""Given the stan and the optional context, return a list of strings and
134
Context instances, optimizing as much static content as possible into contiguous
137
The Context instances will have Tag instances whose .children have also been
140
from nevow.context import WovenContext
141
newctx = WovenContext(precompile=True)
143
macroFactory = inevow.IMacroFactory(ctx, None)
144
if macroFactory is not None:
145
newctx.remember(macroFactory, inevow.IMacroFactory)
147
list(iterflatten(stan, newctx, doc.append))