Formal was a library independently distributed with nevow. Since upstream nevow development ceased and formal has been unmaintained for a long time before that, we've now adopted formal into DaCHS, and we've added nevowc, a minimal set of changes to let simple nevow code run with current twisted.web with a reasonable number of modifications. Porting Guide ============= nevow templates should work unmodified, *except*: * using n:render="" when data is a dictionary instead of using a slot no longer works. You can use data="key " (i.e., just write a "key " in front of the attribute) instead. Non-trivial code, on the other hand, will need to be changed. In particular, render methods may no longer return deferreds or other resources, which ruins many common patterns. Really sorry about that, but that's what twisted.web does. renderHTTP(self, ctx) -> render_GET(self, request) If you returned a deferred so far, do something like: from twisted.web import NOT_DONE_YET d = d.addErrback() d.addBoth(lambda ignored: request.finish()) return NOT_DONE_YET If you returned another resource, either figure that resource out in your getChild method and return it from there, or call its render method from within yours. rend.Page -> nevowc.TemplatedPage if you used templating, t.w.resource.Resource otherwise. formal.ResourceMixin -> formal.ResourceWithForm; that's no longer a mixin but instead inherits from nevowc.TemplatedPage. data_foo(self, ctx, data) -- data functions now have the signature (self, request, tag). To obtain what used to be in the data argument (the "current data"), use tag.slotData (which no longer is necessarily a dict). As before, you can also just accept a single argument and then return a function f(req, tag) -> anything. render_foo(self, ctx, data) -> @template.renderer def foo(self, request, tag) -- render function now have the signature self, request, tag, and as with data functions, what used to be data is in tag.slotData. Warning: when you do that, it's really common that the new method name clashes with an existing attribute ("self.form"). That gives confusing error messages, so beware. from nevow.loaders import XMLFile -> from nevowc import XMLFile similar for XMLString. For loaders.stan , use twisted.web.template.TagLoader; the twisted.web tags are monkeypatched to provide elementary backwards compatibility. docFactory -> loader iformal.IFormData(ctx) -> form.data iformal.IFormErrors(ctx) -> form.errors getPostCharset(ctx) -> 'utf-8' (we've dropped all pretenses of supporting anything else; we believe that's not been an actual problem for around a decade or so). from nevow import appserver -> from twisted.web import server appserver.errorMarker -- gone; render will return as usual even in the error case. flat.flatten(stan) -> t.w.template.flatten rend.Fragment -> t.w.template.Element; change docFactory to loader, and mix in nevowc.CommonRenderer if you use render="mapping" and friends. T.invisible -> T.transparent T.slot -> template.slot T.directive -> (nothing) Just just the strings as they are T.something(data="foo") -> nevowc.addNevowAttributes(T.something, data="foo") T.something(pattern="foo") -> nevowc.addNevowAttributes( T.something, pattern="foo") render=rend.sequence -> render="sequence" render=rend.mapping -> render="mapping" from nevow import tags as T -> from twisted.web.template import tags as T from nevow import entities as E - gone. Use unicode characters. Or, if all else fails, nevowc.xml. from nevow import static -> from twisted.web import static inevow.IContainer -> nccompat.IContainer url.URL.fromContext(ctx) -> request.URLPath() url.clear() -> url.query = None (or so I think) nevow.appserver.NevowSite -> twisted.web.server.Site inevow.IRequest(ctx) -- ctx is gone, so you should have request from the start. return url.URL(...) -> return twisted.web.util.Redirect(...) inevow.ICanHandleException -- gone. Override request.processingFailed (or errbacks) inevow.IRenderer -> t.w.iweb.IRenderable (and, of course, you need to fix the interface) locateChild(ctx, segments) ->getChild(name, request); name is segments[0], the remaining segments you can only get through request.postpath. Return another resource or t.w.resource.NoResource() for a 404; in particular, you no longer return any unconsumed segments with the resource. request.finishRequest() -> request.finish() n:render="data" -> n:render="string" * No context any more (that hurts a lot, but since since twisted.web doesn't have it any more, still supporting it would have been really painful. * Precompilation is no longer supported. * Missing renderers will result in AttributeErrors * No nested/chained contexts any more. * I've generally tried to cut down on components; I found it made the code a lot more magic without giving a proportional benefit. Sorry to the original implementors -- I know it feels like a great idea. * Assuming utf-8 as POSTCharset througout (TODO: make sure accept-charset is properly set) * We don't support Page.childFactory any more. * You can't return Deferreds from locateChild any more