![](https://secure.gravatar.com/avatar/4b38f6c82461bc349f7ce95040bd67cc.jpg?s=120&d=mm&r=g)
Should it be possible to nest nevow:data declarations in a template? E.g. <html nevow:data="order" nevow:render="order"> <head><title>Order <nevow:slot name="order_number"/></title></head> <body> <h1>Order <nevow:slot name="order_number"/></h1> <ul nevow:data="order_items" nevow:render="sequence"> <li nevow:pattern="item" nevow:render="mapping"> ... slots and stuff </li> </ul> </body> When I do this I get a big long stack trace rooted in nevow/accessors.py. It works fine if I remove the outer nevow:data="order" (and dummy up a static fillSlots call for "order_number" in render_order). It also works if I remove the inner section. I can work around the problem by putting the nevow:data="order" declaration in multiple places but it would be handy if I didn't have to. Is this a bug or is it by design?
![](https://secure.gravatar.com/avatar/fa0d5afe9854289a5c4724e724eb74c3.jpg?s=120&d=mm&r=g)
It is possible. The problem is probably elsewhere, perhaps one of the methods is misbehaving or does not exist. It can often be hard to tell from the traceback because almost everything in nevow is deferred, so the problem is not manifest until long after it was encountered. On Mon, Aug 02, 2004 at 10:36:40AM -0700, Jeff Bowden wrote:
Should it be possible to nest nevow:data declarations in a template? E.g.
<html nevow:data="order" nevow:render="order"> <head><title>Order <nevow:slot name="order_number"/></title></head> <body> <h1>Order <nevow:slot name="order_number"/></h1> <ul nevow:data="order_items" nevow:render="sequence"> <li nevow:pattern="item" nevow:render="mapping"> ... slots and stuff </li> </ul> </body>
When I do this I get a big long stack trace rooted in nevow/accessors.py. It works fine if I remove the outer nevow:data="order" (and dummy up a static fillSlots call for "order_number" in render_order). It also works if I remove the inner section.
I can work around the problem by putting the nevow:data="order" declaration in multiple places but it would be handy if I didn't have to. Is this a bug or is it by design?
![](https://secure.gravatar.com/avatar/6721e7c2fc10f17fcdda8c40f46797c6.jpg?s=120&d=mm&r=g)
On Aug 2, 2004, at 1:36 PM, Jeff Bowden wrote:
Should it be possible to nest nevow:data declarations in a template? E.g.
<html nevow:data="order" nevow:render="order"> <head><title>Order <nevow:slot name="order_number"/></title></head> <body> <h1>Order <nevow:slot name="order_number"/></h1> <ul nevow:data="order_items" nevow:render="sequence"> <li nevow:pattern="item" nevow:render="mapping"> ... slots and stuff </li> </ul> </body>
When I do this I get a big long stack trace rooted in nevow/accessors.py. It works fine if I remove the outer nevow:data="order" (and dummy up a static fillSlots call for "order_number" in render_order). It also works if I remove the inner section.
I can work around the problem by putting the nevow:data="order" declaration in multiple places but it would be handy if I didn't have to. Is this a bug or is it by design?
What type is "order"? A data directive puts that data on the context stack for the duration of that xml node; additional data directives are handled by getting an IContainer adapter around the nearest data on the stack. If, as I am suspecting, "order" is a rich python class, what you want to do is either mix in DataFactory to your order class and declare that it implements IContainer, or provide an IContainer adapter for your order class (which is probably a subclass of DataFactory). For example: class OrderContainer(DataFactory): def data_order_number(self, ctx, data): return self.original.orderNumber def data_order_items(self, ctx, data): return self.original.items compy.registerAdapter(OrderContainer, MyOrderClass, IContainer) This is by design. It's intended to work in such a way that fragments of template can have data pushed at them, and they can operate without knowledge of the context of the entire page. The biggest mistake people make in this area is when they do something like push a list onto the context and then try to access another data_ method of the Page class. The directive will be satisfied by doing IContainer(theList).child(theDirective), and since the IContainer adapter for lists doesn't know how to handle anything except integer indexes, they get an exception. eg: <ol n:data="someList" n:render="sequence"> <li n:pattern="header" n:data="someOtherDirective"> <!-- This won't work because "someList" is the topmost data on the stack, and thus we will get an exception instead of having our data_someOtherDirective method called on our Page --> Header here </li> <li n:pattern="item" n:render="string"> Items here </li> </ol> Woven used to have a syntax which used ".." and "/" to allow you to navigate through the stuff on the data stack, but this hasn't yet been implemented in nevow. It may be at some point in the future. For now, the broken example above could be written like: <ol> <li n:data="someOtherDirective"> Header here </li> <n:invisible n:data="someList" n:render="sequence"> <li n:pattern="item" n:render="string"> Items here </li> </n:invisible> </ol> dp
![](https://secure.gravatar.com/avatar/4b38f6c82461bc349f7ce95040bd67cc.jpg?s=120&d=mm&r=g)
Donovan Preston wrote:
On Aug 2, 2004, at 1:36 PM, Jeff Bowden wrote:
Should it be possible to nest nevow:data declarations in a template? E.g.
<html nevow:data="order" nevow:render="order"> <head><title>Order <nevow:slot name="order_number"/></title></head> <body> <h1>Order <nevow:slot name="order_number"/></h1> <ul nevow:data="order_items" nevow:render="sequence"> <li nevow:pattern="item" nevow:render="mapping"> ... slots and stuff </li> </ul> </body>
When I do this I get a big long stack trace rooted in nevow/accessors.py. It works fine if I remove the outer nevow:data="order" (and dummy up a static fillSlots call for "order_number" in render_order). It also works if I remove the inner section.
I can work around the problem by putting the nevow:data="order" declaration in multiple places but it would be handy if I didn't have to. Is this a bug or is it by design?
What type is "order"? A data directive puts that data on the context stack for the duration of that xml node; additional data directives are handled by getting an IContainer adapter around the nearest data on the stack. If, as I am suspecting, "order" is a rich python class, what you want to do is either mix in DataFactory to your order class and declare that it implements IContainer, or provide an IContainer adapter for your order class (which is probably a subclass of DataFactory). For example:
class OrderContainer(DataFactory): def data_order_number(self, ctx, data): return self.original.orderNumber
def data_order_items(self, ctx, data): return self.original.items
compy.registerAdapter(OrderContainer, MyOrderClass, IContainer)
This is by design. It's intended to work in such a way that fragments of template can have data pushed at them, and they can operate without knowledge of the context of the entire page.
The biggest mistake people make in this area is when they do something like push a list onto the context and then try to access another data_ method of the Page class. The directive will be satisfied by doing IContainer(theList).child(theDirective), and since the IContainer adapter for lists doesn't know how to handle anything except integer indexes, they get an exception.
eg:
<ol n:data="someList" n:render="sequence"> <li n:pattern="header" n:data="someOtherDirective"> <!-- This won't work because "someList" is the topmost data on the stack, and thus we will get an exception instead of having our data_someOtherDirective method called on our Page --> Header here </li> <li n:pattern="item" n:render="string"> Items here </li> </ol>
So you are saying is that a nested data directive will try to reference the outer data directive rather than the page class? Wow, I'm glad I asked. I wouldn't have guessed that based on the tutorial. Is there a high-level overview or diagram somewhere of how all pieces of Nevow fit together? OK anyway so yeah, as you guessed, "order" is a python list and the exception I get matches your description exactly. The OrderContainer(DataFactory) suggestion seems like a conceptually clean solution for my current task but it won't be quite so tidy when I go to nest *it* inside of a more-or-less unrelated outer directive, which is my next step. Maybe I'll make a data container that just passes through requests to the page and wraps them in a new instance of itself before returning them (i.e. simple nesting with no implied relationship between inner and outer scopes).
![](https://secure.gravatar.com/avatar/4b38f6c82461bc349f7ce95040bd67cc.jpg?s=120&d=mm&r=g)
I made a little app to try to try to get nested data declarations working (attached). The app works if I remove nevow:data="outer" from the template (render_outer doesn't depend on any data) but otherwise it complains: nevow.accessors.NoAccessor: None does not implement IContainer, and there is no registered adapter. My expectation was that since data_outer just returns self this should just mean that there are two copies of the TestPage instance on the context stack. Apparently my understanding is wrong. Are there any working examples of nested data declarations out there? from twisted.application import service, internet from nevow import rend, loaders, appserver class TestPage(rend.Page): docFactory = loaders.htmlfile("testpage.html") def __init__(self): rend.Page.__init__(self) def data_outer(self, context, data): return self def data_inner(self, context, data): return [{'prop.1': 'data1', 'prop.2': 'data2'}] def render_outer(self, context, data): context.fillSlots("outer.title", "I'm soooo outer") return context.tag site = appserver.NevowSite(TestPage()) application = service.Application("example") internet.TCPServer(8086, site).setServiceParent(application)
![](https://secure.gravatar.com/avatar/4b38f6c82461bc349f7ce95040bd67cc.jpg?s=120&d=mm&r=g)
So is the behaviour I described below a bug or am I doing something wrong? Jeff Bowden wrote:
I made a little app to try to try to get nested data declarations working (attached). The app works if I remove nevow:data="outer" from the template (render_outer doesn't depend on any data) but otherwise it complains:
nevow.accessors.NoAccessor: None does not implement IContainer, and there is no registered adapter.
My expectation was that since data_outer just returns self this should just mean that there are two copies of the TestPage instance on the context stack. Apparently my understanding is wrong. Are there any working examples of nested data declarations out there?
------------------------------------------------------------------------
from twisted.application import service, internet from nevow import rend, loaders, appserver
class TestPage(rend.Page): docFactory = loaders.htmlfile("testpage.html") def __init__(self): rend.Page.__init__(self)
def data_outer(self, context, data): return self
def data_inner(self, context, data): return [{'prop.1': 'data1', 'prop.2': 'data2'}]
def render_outer(self, context, data): context.fillSlots("outer.title", "I'm soooo outer") return context.tag
site = appserver.NevowSite(TestPage())
application = service.Application("example") internet.TCPServer(8086, site).setServiceParent(application)
------------------------------------------------------------------------
Title: TITLE
* prop.1 - prop.2
------------------------------------------------------------------------
_______________________________________________ Twisted-web mailing list Twisted-web@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web
participants (3)
-
Donovan Preston
-
Jeff Bowden
-
Phil Frost