/usr/share/pyshared/nevow/rend.py is in python-nevow 0.10.0-4build1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 | # Copyright (c) 2004 Divmod.
# See LICENSE for details.
"""Page, Fragment and other standard renderers.
This module contains classes and function responsible for rendering
dynamic content and a few useful mixin classes for inheriting common
functionality.
Mostly, you'll use the renderers:
- B{Page} - Nevow's main resource type for rendering web pages and
locating child resource.
- B{Fragment} - useful for rendering more complex parts of a document
that require a set of data_* and render_* methods.
- B{sequence} - render each item in a sequence.
- B{mapping} - publish a dictionary by filling slots
"""
from time import time as now
from cStringIO import StringIO
import random
import warnings
from zope.interface import implements, providedBy
import twisted.python.components as tpc
from twisted.python.reflect import qual, accumulateClassList
from nevow.context import WovenContext, NodeNotFound, PageContext
from nevow import inevow, tags, flat, util, url
from nevow.util import log
import formless
from formless import iformless, annotate
def _getPreprocessors(inst):
"""
Accumulate elements from the sequences bound at the C{preprocessors}
attribute on all classes in the inheritance hierarchy of the class of
C{inst}. A C{preprocessors} attribute on the given instance overrides
all preprocessors from the class inheritance hierarchy.
"""
if 'preprocessors' in vars(inst):
return inst.preprocessors
preprocessors = []
accumulateClassList(
inst.__class__,
'preprocessors',
preprocessors)
return preprocessors
class RenderFactory(object):
implements(inevow.IRendererFactory)
def renderer(self, context, name):
"""Return a renderer with the given name.
"""
# The named renderer can be parameterised, i.e. 'renderIt one,two,three'
args = []
if name.find(' ') != -1:
name, args = name.split(None, 1)
args = [arg.strip() for arg in args.split(',')]
callable = getattr(self, 'render_%s' % name, None)
if callable is None:
warnings.warn(
"Renderer %r missing on %s will result in an exception." % (
name, qual(type(self))),
category=DeprecationWarning,
stacklevel=1)
callable = lambda *a, **kw: context.tag[
"The renderer named '%s' was not found in %r." % (name, self)]
if args:
return callable(*args)
return callable
render_sequence = lambda self, context, data: sequence(context, data)
render_mapping = lambda self, context, data: mapping(context, data)
render_string = lambda self, context, data: string(context, data)
render_xml = lambda self, context, data: context.tag.clear()[tags.xml(data)]
render_data = lambda self, context, data_: data(context, data_)
class MacroFactory(object):
implements(inevow.IMacroFactory)
def macro(self, ctx, name):
"""Return a macro with the given name.
"""
# The named macro can be parameterized, i.e. 'macroFoo foo,bar,baz'
args = []
if name.find(' ') != -1:
name, args = name.split(None, 1)
args = [arg.strip() for arg in args.split(',')]
callable = getattr(self, 'macro_%s' % name, None)
if callable is None:
callable = lambda ctx, *args: ctx.tag[
"The macro named '%s' was not found in %r." % (name, self)]
if args:
## Macros are expanded in TagSerializer by calling them with a single arg, the context
return lambda ctx: callable(ctx, *args)
return callable
class DataNotFoundError(Exception):
"""Raised when a data directive could not be resolved on the page or its
original attribute by the DataFactory.
"""
class DataFactory(object):
implements(inevow.IContainer)
def child(self, context, n):
args = []
if n.find(' ') != -1:
name, args = n.split(None, 1)
args = [arg.strip() for arg in args.split(',')]
else:
name = n
callable = getattr(self, 'data_%s' % name, None)
## If this page doesn't have an appropriate data_* method...
if callable is None:
## See if our self.original has an IContainer...
container = inevow.IContainer(self.original, None)
if container is None:
raise DataNotFoundError("The data named %r was not found in %r." % (name, self))
else:
## And delegate to it if so.
return container.child(context, n)
if args:
return callable(*args)
return callable
class FreeformChildMixin:
"""Mixin that handles locateChild for freeform segments."""
def locateChild(self, ctx, segments):
request = inevow.IRequest(ctx)
## The method or property name we are going to validate against/affect
bindingName = None
name = segments[0]
if name.startswith('freeform_post!'):
configurableName, bindingName = name.split('!')[1:3]
elif name.startswith('freeform-action-post!'):
configurableName, request.args['freeform-actee'] = name.split('!')[1:3]
bindingName = request.args['freeform-action'][0]
if bindingName:
ctx.remember(self, inevow.IResource)
ctx.remember(request, inevow.IRequest)
cf = iformless.IConfigurableFactory(self)
def checkC(c):
if c is not None:
return self.webFormPost(request, self, c, ctx, bindingName, request.args)
return util.maybeDeferred(cf.locateConfigurable, ctx, configurableName).addCallback(checkC)
return NotFound
def child_freeform_hand(self, ctx):
carryoverHand = inevow.IHand(ctx, None)
if carryoverHand is not None:
inevow.ISession(ctx).setComponent(inevow.IHand, carryoverHand)
return carryoverHand
return inevow.IHand(inevow.ISession(ctx), None)
class ConfigurableMixin(object):
"""
A sane L{IConfigurable} implementation for L{Fragment} and L{Page}.
Methods starting with C{bind_} automatically expose corresponding method
names. C{bind_*} should return an L{IBinding} (L{PropertyBinding} or
L{MethodBinding}), or, as a shortcut for L{MethodBinding}, a C{list} of
two-C{tuples} like this::
def bind_foo(self, ctx):
return [('argName', String()), ('anotherArg', Integer())]
def foo(self, argName, anotherArg):
assert isinstance(argName, str)
assert isinstance(anotherArg, int)
"""
implements(iformless.IConfigurable)
def getBindingNames(self, ctx):
"""Expose bind_* methods and attributes on this class.
"""
for name in dir(self):
if name.startswith('bind_'):
yield name[len('bind_'):]
def getBinding(self, ctx, name):
"""Massage bind_* methods and attributes into an
IBinding. The bind_* method or attribute can either
already implement IBinding or be a list of twoples
which will be massaged into a MethodBinding as
described in the ConfigurableMixin class docstring.
"""
def _get_binding(binding):
if callable(binding):
binding = util.maybeDeferred(binding, ctx)
return binding
def _convert_list(binding):
if isinstance(binding, list):
binding = annotate.MethodBinding(
name, annotate.Method(arguments=[
annotate.Argument(n, v, v.id)
for (n, v) in binding]))
return binding
binding = util.maybeDeferred(getattr, self, 'bind_%s' % name)
return binding.addCallback(_get_binding).addCallback(_convert_list)
def getDefault(self, forBinding):
"""Get a default value for a given binding. If the
binding is a Property, get the current value of
that property off self. If not, simply return
forBinding.default.
"""
## If it is a Property, get the value off self
if not isinstance(forBinding, annotate.Argument):
if hasattr(self, forBinding.name):
return getattr(self, forBinding.name)
return forBinding.default
def postForm(self, ctx, bindingName, args):
"""Accept a form post to the given bindingName.
The post arguments are given in args.
This will invoke the IInputProcessor for the
binding with the given name. If it succeeds, the
property will be modified or the method will have
been called. If it fails, a ValidateError exception
will be raised.
"""
def _callback(binding):
ctx.remember(binding, iformless.IBinding)
ctx.remember(self, iformless.IConfigurable)
rv = iformless.IInputProcessor(binding).process(ctx, self, args)
ctx.remember(rv, inevow.IHand)
ctx.remember('%r success.' % bindingName, inevow.IStatusMessage)
return rv
return util.maybeDeferred(self.getBinding, ctx,
bindingName).addCallback(_callback)
class ConfigurableFactory:
"""Locates configurables by looking for methods that start with
configurable_ and end with the name of the configurable. The method
should take a single arg (other than self) - the current context.
"""
implements(iformless.IConfigurableFactory)
def locateConfigurable(self, context, name):
"""formless.webform.renderForms calls locateConfigurable on the IConfigurableFactory
instance it retrieves from the context. It passes the "name" that was passed to it,
so if renderForms() was placed in the DOM, locateConfigurable will be called with
name = ''; if renderForms('foo') was placed in the DOM, locateConfigurable will
be called with name = 'foo'.
This default implementation of locateConfigurable looks for a configurable_* method
corresponding to the name which was passed.
"""
return util.maybeDeferred(getattr(self, 'configurable_%s'%name),
context).addCallback(iformless.IConfigurable)
def configurable_(self, context):
"""Configurable factory for use when self is a configurable;
aka it implements IConfigurable or one or more TypedInterface
subclasses. Usage:
>>> class IFoo(TypedInterface):
... def bar(): pass
... bar = autocallable(bar)
...
>>> class Foo(Page):
... implements(IFoo)
...
... def bar():
... print "bar called through the web!"
...
... def render_forms(self, ctx, data):
... return renderForms() # or renderForms('')
...
... docFactory = stan(render_forms).
"""
if filter(lambda x: issubclass(x, annotate.TypedInterface), providedBy(self)):
warnings.warn("[0.5] Subclassing TypedInterface to declare annotations is deprecated. Please provide bind_* methods on your Page or Fragment subclass instead.", DeprecationWarning)
from formless import configurable
return configurable.TypedInterfaceConfigurable(self)
return self
def configurable_original(self, ctx):
"""Configurable factory for use when self.original is a configurable;
aka it implements IConfigurable or one or more TypedInterface
subclasses. Usage:
>>> class Foo(Page):
... def __init__(self):
... self.original = SomeConfigurable()
... def render_forms(self, ctx, data):
... return renderForms('original')
... docFactory = stan(render_forms)
"""
return self.original
_CARRYOVER = {}
def defaultsFactory(ctx):
co = _CARRYOVER.get(
ctx.tag.args.get('_nevow_carryover_', [None])[0], None)
from formless import webform
defaults = webform.FormDefaults()
if co is not None:
e = iformless.IFormErrors(co, {})
for k, v in e.items():
defaults.getAllDefaults(k).update(v.partialForm)
return defaults
def errorsFactory(ctx):
co = _CARRYOVER.get(
ctx.tag.args.get('_nevow_carryover_', [None])[0], None)
from formless import webform
errs = webform.FormErrors()
if co is not None:
e = iformless.IFormErrors(co, {})
for k, v in e.items():
errs.updateErrors(k, v.errors)
errs.setError(k, v.formErrorMessage)
return errs
def handFactory(ctx):
co = _CARRYOVER.get(
ctx.tag.args.get('_nevow_carryover_', [None])[0], None)
return inevow.IHand(co, None)
def statusFactory(ctx):
co = _CARRYOVER.get(
ctx.tag.args.get('_nevow_carryover_', [None])[0], None)
return inevow.IStatusMessage(co, None)
def originalFactory(ctx):
return ctx.tag
class Fragment(DataFactory, RenderFactory, MacroFactory, ConfigurableMixin):
"""
This class is deprecated because it relies on context objects
U{which are being removed from Nevow<http://divmod.org/trac/wiki/WitherContext>}.
@see: L{Element}
"""
implements(inevow.IRenderer, inevow.IGettable)
docFactory = None
original = None
def __init__(self, original=None, docFactory=None):
if original is not None:
self.original = original
self.toremember = []
if docFactory is not None:
self.docFactory = docFactory
def get(self, context):
return self.original
def rend(self, context, data):
# Create a new context so the current context is not polluted with
# remembrances.
context = WovenContext(parent=context)
# Remember me as lots of things
self.rememberStuff(context)
preprocessors = _getPreprocessors(self)
# This tidbit is to enable us to include Page objects inside
# stan expressions and render_* methods and the like. But
# because of the way objects can get intertwined, we shouldn't
# leave the pattern changed.
old = self.docFactory.pattern
self.docFactory.pattern = 'content'
self.docFactory.precompiledDoc = None
try:
try:
doc = self.docFactory.load(context, preprocessors)
finally:
self.docFactory.pattern = old
self.docFactory.precompiledDoc = None
except TypeError, e:
# Avert your eyes now! I don't want to catch anything but IQ
# adaption exceptions here but all I get is TypeError. This whole
# section of code is a complete hack anyway so one more won't
# matter until it's all removed. ;-).
if 'nevow.inevow.IQ' not in str(e):
raise
doc = self.docFactory.load(context, preprocessors)
except NodeNotFound:
doc = self.docFactory.load(context, preprocessors)
else:
if old == 'content':
warnings.warn(
"""[v0.5] Using a Page with a 'content' pattern is
deprecated.""",
DeprecationWarning,
stacklevel=2)
context.tag = tags.invisible[doc]
return context
def remember(self, obj, inter=None):
"""Remember an object for an interface on new PageContexts which are
constructed around this Page. Whenever this Page is involved in object
traversal in the future, all objects will be visible to .locate() calls
at the level of a PageContext wrapped around this Page and all contexts
below it.
This does not affect existing Context instances.
"""
self.toremember.append((obj, inter))
def rememberStuff(self, ctx):
ctx.remember(self, inevow.IRenderer)
ctx.remember(self, inevow.IRendererFactory)
ctx.remember(self, inevow.IMacroFactory)
ctx.remember(self, inevow.IData)
class ChildLookupMixin(FreeformChildMixin):
##
# IResource methods
##
children = None
def locateChild(self, ctx, segments):
"""Locate a child page of this one. ctx is a
nevow.context.PageContext representing the parent Page, and segments
is a tuple of each element in the URI. An tuple (page, segments) should be
returned, where page is an instance of nevow.rend.Page and segments a tuple
representing the remaining segments of the URI. If the child is not found, return
NotFound instead.
locateChild is designed to be easily overridden to perform fancy lookup tricks.
However, the default locateChild is useful, and looks for children in three places,
in this order:
- in a dictionary, self.children
- a member of self named child_<childname>. This can be either an
attribute or a method. If an attribute, it should be an object which
can be adapted to IResource. If a method, it should take the context
and return an object which can be adapted to IResource.
- by calling self.childFactory(ctx, name). Name is a single string instead
of a tuple of strings. This should return an object that can be adapted
to IResource.
"""
if self.children is not None:
r = self.children.get(segments[0], None)
if r is not None:
return r, segments[1:]
w = getattr(self, 'child_%s'%segments[0], None)
if w is not None:
if inevow.IResource(w, None) is not None:
return w, segments[1:]
r = w(ctx)
if r is not None:
return r, segments[1:]
r = self.childFactory(ctx, segments[0])
if r is not None:
return r, segments[1:]
return FreeformChildMixin.locateChild(self, ctx, segments)
def childFactory(self, ctx, name):
"""Used by locateChild to return children which are generated
dynamically. Note that higher level interfaces use only locateChild,
and only nevow.rend.Page.locateChild uses this.
segment is a string representing one element of the URI. Request is a
nevow.appserver.NevowRequest.
The default implementation of this always returns None; it is intended
to be overridden."""
return None
def putChild(self, name, child):
if self.children is None:
self.children = {}
self.children[name] = child
class Page(Fragment, ConfigurableFactory, ChildLookupMixin):
"""A page is the main Nevow resource and renders a document loaded
via the document factory (docFactory).
"""
implements(inevow.IResource)
buffered = False
beforeRender = None
afterRender = None
addSlash = None
flattenFactory = lambda self, *args: flat.flattenFactory(*args)
def renderHTTP(self, ctx):
if self.beforeRender is not None:
return util.maybeDeferred(self.beforeRender,ctx).addCallback(
lambda result,ctx: self._renderHTTP(ctx),ctx)
return self._renderHTTP(ctx)
def _renderHTTP(self, ctx):
request = inevow.IRequest(ctx)
## XXX request is really ctx now, change the name here
if self.addSlash and inevow.ICurrentSegments(ctx)[-1] != '':
request.redirect(request.URLPath().child(''))
return ''
log.msg(http_render=None, uri=request.uri)
self.rememberStuff(ctx)
def finishRequest():
carryover = request.args.get('_nevow_carryover_', [None])[0]
if carryover is not None and _CARRYOVER.has_key(carryover):
del _CARRYOVER[carryover]
if self.afterRender is not None:
return util.maybeDeferred(self.afterRender,ctx)
if self.buffered:
io = StringIO()
writer = io.write
def finisher(result):
request.write(io.getvalue())
return util.maybeDeferred(finishRequest).addCallback(lambda r: result)
else:
writer = request.write
def finisher(result):
return util.maybeDeferred(finishRequest).addCallback(lambda r: result)
preprocessors = _getPreprocessors(self)
doc = self.docFactory.load(ctx, preprocessors)
ctx = WovenContext(ctx, tags.invisible[doc])
return self.flattenFactory(doc, ctx, writer, finisher)
def rememberStuff(self, ctx):
Fragment.rememberStuff(self, ctx)
ctx.remember(self, inevow.IResource)
def renderString(self, ctx=None):
"""Render this page outside of the context of a web request, returning
a Deferred which will result in a string.
If twisted is not installed, this method will return a string result immediately,
and this method is equivalent to renderSynchronously.
"""
io = StringIO()
writer = io.write
def finisher(result):
return io.getvalue()
ctx = PageContext(parent=ctx, tag=self)
self.rememberStuff(ctx)
doc = self.docFactory.load(ctx)
ctx = WovenContext(ctx, tags.invisible[doc])
return self.flattenFactory(doc, ctx, writer, finisher)
def renderSynchronously(self, ctx=None):
"""Render this page synchronously, returning a string result immediately.
Raise an exception if a Deferred is required to complete the rendering
process.
"""
io = StringIO()
ctx = PageContext(parent=ctx, tag=self)
self.rememberStuff(ctx)
doc = self.docFactory.load(ctx)
ctx = WovenContext(ctx, tags.invisible[doc])
def raiseAlways(item):
raise NotImplementedError("renderSynchronously can not support"
" rendering: %s" % (item, ))
list(flat.iterflatten(doc, ctx, io.write, raiseAlways))
return io.getvalue()
def child_(self, ctx):
"""When addSlash is True, a page rendered at a url with no
trailing slash and a page rendered at a url with a trailing
slash will be identical. addSlash is useful for the root
resource of a site or directory-like resources.
"""
# Only allow an empty child, by default, if it's on the end
# and we're a directoryish resource (addSlash = True)
if self.addSlash and len(inevow.IRemainingSegments(ctx)) == 1:
return self
return None
def webFormPost(self, request, res, configurable, ctx, bindingName, args):
"""Accept a web form post, either redisplaying the original form (with
errors) if validation fails, or redirecting to the appropriate location after
the post succeeds. This hook exists specifically for formless.
New in 0.5, _nevow_carryover_ is only used if an autocallable method
returns a result that needs to be carried over.
New in 0.5, autocallables may return a nevow.url.URL or URLOverlay
instance rather than setting IRedirectAfterPost on the request.
New in 0.5, autocallables may return a Page instance to have that Page
instance rendered at the post target URL with no redirects at all. Useful
for multi-step wizards.
"""
def redirectAfterPost(aspects):
hand = aspects.get(inevow.IHand)
refpath = None
if hand is not None:
if isinstance(hand, Page):
refpath = url.here
if 'freeform_hand' not in inevow.IRequest(ctx).prepath:
refpath = refpath.child('freeform_hand')
if isinstance(hand, (url.URL, url.URLOverlay)):
refpath, hand = hand, None
if refpath is None:
redirectAfterPost = request.getComponent(iformless.IRedirectAfterPost, None)
if redirectAfterPost is None:
ref = request.getHeader('referer')
if ref:
refpath = url.URL.fromString(ref)
else:
refpath = url.here
else:
warnings.warn("[0.5] IRedirectAfterPost is deprecated. Return a URL instance from your autocallable instead.", DeprecationWarning, 2)
## Use the redirectAfterPost url
ref = str(redirectAfterPost)
refpath = url.URL.fromString(ref)
if hand is not None or aspects.get(iformless.IFormErrors) is not None:
magicCookie = '%s%s%s' % (now(),request.getClientIP(),random.random())
refpath = refpath.replace('_nevow_carryover_', magicCookie)
_CARRYOVER[magicCookie] = C = tpc.Componentized()
for k, v in aspects.iteritems():
C.setComponent(k, v)
destination = flat.flatten(refpath, ctx)
request.redirect(destination)
from nevow import static
return static.Data('You posted a form to %s' % bindingName, 'text/plain'), ()
return util.maybeDeferred(
configurable.postForm, ctx, bindingName, args
).addCallback(
self.onPostSuccess, request, ctx, bindingName, redirectAfterPost
).addErrback(
self.onPostFailure, request, ctx, bindingName, redirectAfterPost
)
def onPostSuccess(self, result, request, ctx, bindingName, redirectAfterPost):
if result is None:
message = "%s success." % formless.nameToLabel(bindingName)
else:
message = result
return redirectAfterPost({inevow.IHand: result, inevow.IStatusMessage: message})
def onPostFailure(self, reason, request, ctx, bindingName, redirectAfterPost):
reason.trap(formless.ValidateError)
return redirectAfterPost({iformless.IFormErrors: {bindingName: reason.value}})
def sequence(context, data):
"""Renders each item in the sequence using patterns found in the
children of the element.
Sequence recognises the following patterns:
- header: Rendered at the start, before the first item. If multiple
header patterns are provided they are rendered together in the
order they were defined.
- footer: Just like the header only renderer at the end, after the
last item.
- item: Rendered once for each item in the sequence. If multiple
item patterns are provided then the pattern is cycled in the
order defined.
- divider: Rendered once between each item in the sequence. Multiple
divider patterns are cycled.
- empty: Rendered instead of item and divider patterns when the
sequence contains no items.
Example::
<table nevow:render="sequence" nevow:data="peopleSeq">
<tr nevow:pattern="header">
<th>name</th>
<th>email</th>
</tr>
<tr nevow:pattern="item" class="odd">
<td>name goes here</td>
<td>email goes here</td>
</tr>
<tr nevow:pattern="item" class="even">
<td>name goes here</td>
<td>email goes here</td>
</tr>
<tr nevow:pattern="empty">
<td colspan="2"><em>they've all gone!</em></td>
</tr>
</table>
"""
tag = context.tag
headers = tag.allPatterns('header')
pattern = tag.patternGenerator('item')
divider = tag.patternGenerator('divider', default=tags.invisible)
content = [(pattern(data=element), divider(data=element)) for element in data]
if not content:
content = tag.allPatterns('empty')
else:
## No divider after the last thing.
content[-1] = content[-1][0]
footers = tag.allPatterns('footer')
return tag.clear()[ headers, content, footers ]
def mapping(context, data):
"""Fills any slots in the element's children with data from a
dictionary. The dict keys are used as the slot names, the dict
values are used as filling.
Example::
<tr nevow:render="mapping" nevow:data="personDict">
<td><nevow:slot name="name"/></td>
<td><nevow:slot name="email"/></td>
</tr>
"""
for k, v in data.items():
context.fillSlots(k, v)
return context.tag
def string(context, data):
return context.tag.clear()[str(data)]
def data(context, data):
"""Replace the tag's content with the current data.
"""
return context.tag.clear()[data]
class FourOhFour:
"""A simple 404 (not found) page.
"""
implements(inevow.IResource)
notFound = "<html><head><title>Page Not Found</title></head><body>Sorry, but I couldn't find the object you requested.</body></html>"
original = None
def locateChild(self, ctx, segments):
return NotFound
def renderHTTP(self, ctx):
inevow.IRequest(ctx).setResponseCode(404)
# Look for an application-remembered handler
try:
notFoundHandler = ctx.locate(inevow.ICanHandleNotFound)
except KeyError, e:
return self.notFound
# Call the application-remembered handler but if there are any errors
# then log it and fallback to the standard message.
try:
return notFoundHandler.renderHTTP_notFound(PageContext(parent=ctx, tag=notFoundHandler))
except:
log.err()
return self.notFound
def __nonzero__(self):
return False
# Not found singleton
NotFound = None, ()
|