[Twisted-web] How to nest LiveElements? (getting a MissingRenderMethod error)

kgi iacovou at gmail.com
Fri Dec 1 07:35:34 CST 2006


Hi there.

I've got a web app that was originally written as a bunch of LiveElements at 
the top level of a LivePage. I want to clean up this code and restructure it 
such that several of the LiveElements are more modular; this entails making 
some of the LiveElements contain other LiveElements.

Now, I could have *sworn* I've done this before, but whatever I try to do now 
I get a nevow.errors.MissingRenderMethod exception.

At the end of this email is a cut-down example that exhibits the behaviour. 
OuterWidget and InnerWidget are two LiveElement objects; they can both exist 
happily in the LivePage, but if you uncomment the div containing an 
innerWidget rendering directive (around line 28) you get:

          File "/usr/lib/python2.4/site-packages/nevow/flat/ten.py", line 70, 
in serialize
            return partialflatten(context, obj)
          File "/usr/lib/python2.4/site-packages/nevow/flat/ten.py", line 61, 
in partialflatten
            return flattener(obj, context)
          File "/usr/lib/python2.4/site-packages/nevow/flat/flatstan.py", line 
261, in DirectiveSerializer
            renderer = rendererFactory.renderer(context, original.name)
          File "/usr/lib/python2.4/site-packages/nevow/page.py", line 78, in 
renderer
            raise MissingRenderMethod(self, name)
        nevow.errors.MissingRenderMethod: (<OuterWidget object at 
0xb763482c>, 'innerWidget')

Can anyone shed any light on this?

There are also seemingly three styles for render methods that I've found. The 
third was kind of guessed from the documentation of nevow.page.Element; I'm 
not sure I've used it correctly, but I seem to recall reading that the 
special "render_" prefixes will be going away and replaced by a renderer() 
registration method, like the expose() method for athena callables.

Which is the preferred form?

    def render_innerWidget ( self, ctx, data ):
        elem = InnerWidget()
        elem.setFragmentParent ( self )
        return elem

   def render_innerWidget ( self, ctx, data ):
        elem = InnerWidget()
        elem.setFragmentParent ( self )
        return ctx.tag[f]

   from nevow.page import renderer
   def innerWidget ( self, request, tag ):
        elem = InnerWidget()
        elem.setFragmentParent ( self )
        return elem
   renderer(items)

Thanks,

Ricky

--


# Run using 'twistd -noy file.py'; point browser to localhost:8080

from nevow import athena
from nevow import stan
from nevow import loaders
from nevow import tags as T
from nevow import flat
from nevow import static


class InnerWidget ( athena.LiveElement ):

    docFactory = loaders.stan (
        T.div (
            render = T.directive ( 'liveElement' ),
            ) [
                T.p ( _class = 'bar' ) [ "This is InnerWidget text" ]
            ]
    )


class OuterWidget ( athena.LiveElement ):

    docFactory = loaders.stan (
        T.div (
            render = T.directive ( 'liveElement' ),
            ) [
                T.p ( _class = "foo" ) [ "This is OuterWidget text" ],
                # I can't create an InnerWidget inside the OuterWidget.
                # T.div ( render = T.directive ( "innerWidget" ) ),
            ]
    )

    def render_innerWidget ( self, ctx, data ):
        elem = InnerWidget()
        elem.setFragmentParent ( self )
        return ctx.tag[f]


class WebApp ( athena.LivePage ):

    DOCTYPE_XHTML = (
        '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" '
        '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
    )

    _css = T.link (
        rel = "stylesheet", type = "text/css", href = "css/style.css"
    )

    docFactory = loaders.stan (
        [
            T.xml ( DOCTYPE_XHTML ),
            T.html [
                T.head ( render = T.directive ( 'liveglue' ) ) [ _css ],
                T.body [
                    T.div ( render = T.directive ( 'outerWidget') ),

                    # But I can create an InnerWidget at the top-level, inside
                    # athena.LivePage.
                    T.div ( render = T.directive ( 'innerWidget') ),
                ]
            ]
        ]
    )
    
    addSlash = True

    def render_outerWidget ( self, ctx, data ):
        f = OuterWidget()
        f.setFragmentParent(self)
        return ctx.tag[f]


    def render_innerWidget ( self, ctx, data ):
        f = InnerWidget()
        f.setFragmentParent(self)
        return ctx.tag[f]


    def child_css ( self, ctx ):
        return static.File ( 'css' )


    def child_js ( self, ctx ):
        return static.File ( 'js' )

    
from twisted.application import service, internet
from nevow import appserver

res = WebApp()

site = appserver.NevowSite ( res )

application = service.Application ( "WebApp" )
webService = internet.TCPServer ( 8080, site )
webService.setServiceParent ( application )

--




More information about the Twisted-web mailing list