
On Tue, 01 Feb 2005 12:58:49 GMT, Valentino Volonghi aka Dialtone <dialtone@divmod.com> wrote: The first version of the patch didn't actually work. But I wrote a new version, also thanks to fzZzy and this time it works although it has a flaw since in weever caching the content slot (which is filled with a Fragment) results in 2 big red Nones and the rendered fragment. As I said in the first mail you can use caching with: t.cached(name=some_sensible_name, lifetime=MAX_LIFE)[cached_content] This patch provides, probably, the finest granularity in caching the rendering. Anyway the patch is below: Index: nevow/tags.py =================================================================== --- nevow/tags.py (revision 1136) +++ nevow/tags.py (working copy) @@ -25,7 +25,7 @@ """ -from nevow.stan import Proto, Tag, directive, raw, xml, CommentProto, invisible, slot, cdata +from nevow.stan import Proto, Tag, directive, raw, xml, CommentProto, invisible, slot, cdata, cached comment = CommentProto() @@ -62,7 +62,9 @@ def inlineJS(s): return script(type="text/javascript", language="JavaScript")[xml('\n//<![CDATA[\n%s\n//]]>\n' % s)] -__all__ = tags + ['invisible', 'comment', '_dir', '_del', '_object', '_map', 'drange', 'Tag', 'directive', 'xml', 'raw', 'slot', 'cdata', 'inlineJS'] + ['_%s' % x for x in range(100)] +__all__ = tags + ['invisible', 'comment', '_dir', '_del', '_object', + '_map', 'drange', 'Tag', 'directive', 'xml', 'raw', + 'slot', 'cached', 'cdata', 'inlineJS'] + ['_%s' % x for x in range(100)] ######################## Index: nevow/flat/flatstan.py =================================================================== --- nevow/flat/flatstan.py (revision 1136) +++ nevow/flat/flatstan.py (working copy) @@ -9,7 +9,7 @@ from nevow import util from nevow.stan import Proto, Tag, xml, directive, Unset, invisible from nevow.inevow import IRenderer, IRendererFactory, IGettable, IData -from nevow.flat import precompile, serialize +from nevow.flat import precompile, serialize, iterflatten from nevow.accessors import convertToData from nevow.context import WovenContext @@ -226,6 +226,56 @@ return serialize(original.default, context) return serialize(data, context) +_CACHE = {} +from time import time as now +from cStringIO import StringIO +from twisted.internet import defer +def CachedSerializer(original, context): + cached = _CACHE.get(original.name, None) + life = now()-original.lifetime + if cached and cached[0] > life: +## print "="*20 +## print cached[0] +## print life +## print "="*20 + yield cached[1] + return +## if cached: +## print "="*20 +## print cached[0] +## print life +## print "="*20 + io = StringIO() + for child in iterflatten(original.children, context, io.write, + lambda item: True): + if isinstance(child, tuple): + childDeferred, childReturner = child + + d = defer.Deferred() ## A new deferred for the outer loop, whose result + ## we don't care about, because we don't want the outer loop to write + ## anything when this deferred fires -- only when the entire for loop + ## has completed and we have all the "children" flattened + + def innerDeferredResultAvailable(result): + childReturner(result) ## Cause the inner iterflatten to continue + d.callback('') ## Cause the outer iterflatten to continue + return '' + + childDeferred.addCallback(innerDeferredResultAvailable) + + ## Make the outer loop wait on our new deferred. + ## We call the new deferred back with '' + ## Which will cause the outer loop to write '' to the request, + ## which doesn't matter. It will then call our "returner", + ## which is just the noop lambda below, because we don't care + ## about the return result of the new deferred, which is just + ## '' + + yield d, lambda result: None + result = io.getvalue() + _CACHE[original.name] = (now(), result) + yield result + def ContextSerializer(original, context): originalContext = original.clone(deep=False) originalContext.precompile = context and context.precompile or False Index: nevow/__init__.py =================================================================== --- nevow/__init__.py (revision 1136) +++ nevow/__init__.py (working copy) @@ -182,6 +182,7 @@ nevow.flat.flatstan.RendererSerializer nevow.inevow.IRenderer nevow.flat.flatstan.DirectiveSerializer nevow.stan.directive nevow.flat.flatstan.SlotSerializer nevow.stan.slot +nevow.flat.flatstan.CachedSerializer nevow.stan.cached nevow.flat.flatstan.ContextSerializer nevow.context.WovenContext nevow.flat.flatstan.DeferredSerializer twisted.internet.defer.Deferred nevow.flat.flatstan.DeferredSerializer twisted.internet.defer.DeferredList Index: nevow/stan.py =================================================================== --- nevow/stan.py (revision 1136) +++ nevow/stan.py (working copy) @@ -119,8 +119,33 @@ """ raise NotImplementedError, "Stan slot instances are not iterable." +class cached(object): + """Marker for cached content + """ + __slots__ = ['name', 'children', 'lifetime'] + def __init__(self, name, lifetime=0): + self.name = name + self.children = [] + self.lifetime = lifetime + def __repr__(self): + return "cached('%s','%s')" % self.name, self.lifetime + + def __getitem__(self, children): + """cached content is what is being cached + """ + if not isinstance(children, (list, tuple)): + children = [children] + self.children.extend(children) + return self + + def __iter__(self): + """Prevent an infinite loop if someone tries to do + for x in cached('foo'): + """ + raise NotImplementedError, "Stan slot instances are not iterable." + class Tag(object): """Tag instances represent XML tags with a tag name, attributes, and children. Tag instances can be constructed using the Prototype