def URLSerializer(original, context): urlContext = WovenContext(parent=context, precompile=context.precompile, inURL=True) if original.scheme: yield "%s://%s" % (original.scheme, original.netloc) for pathsegment in original._qpathlist: yield '/' yield serialize(pathsegment, urlContext) query = original._querylist if query: yield '?' first = True for key, value in query: if not first: yield '&' else: first = False yield serialize(key, urlContext) if value is not None: yield '=' yield serialize(value, urlContext) if original.fragment: yield "#" yield serialize(original.fragment, urlContext)
def test_oldFlattenableOverriddenRend(self): """ Flattening L{Element} instances with an overridden C{rend} method flattened with the old flatten function results in the flattened version of whatever their C{rend} method returns. """ renders = [] class OldStyleElement(Element): docFactory = stan("Hello, world") def rend(self, ctx, data): return invisible(render=directive("foo"))[Element.rend( self, ctx, data)] def foo(self, request, tag): renders.append((self, request)) return p[tag] renderer(foo) result = [] element = OldStyleElement() request = FakeRequest() context = WovenContext() context.remember(request) finished = oldFlatten(element, context, result.append, lambda ign: ign) def cbFinished(ignored): self.assertEqual("".join(result), "<p>Hello, world</p>") self.assertEqual(renders, [(element, request)]) finished.addCallback(cbFinished) return finished
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 process(self, context, boundTo, data, autoConfigure = True): """Knows how to process a dictionary of lists where the dictionary may contain a key with the same name as some of the arguments to the MethodBinding instance. """ typedValue = self.original.typedValue results = {} failures = {} if '----' in data: ## ---- is the "direct object", the one argument you can specify using the command line without saying what the argument name is data[typedValue.arguments[0].name] = data['----'] del data['----'] for binding in typedValue.arguments: name = binding.name try: context = WovenContext(context, faketag) context.remember(binding, iformless.IBinding) results[name] = iformless.IInputProcessor(binding.typedValue).process(context, boundTo, data.get(name, [''])) except formless.InputError as e: results[name] = data.get(name, [''])[0] failures[name] = e.reason if failures: #print "There were validation errors. The errors were: ", failures raise formless.ValidateError(failures, "Error:", results) if autoConfigure: def _except(e): failures[''] = e.reason # self.original.name raise formless.ValidateError(failures, e.reason, results) return exceptblock(self.original.configure, _except, formless.InputError, boundTo, results) return results
def patternContext(self, ctx, name): context = WovenContext(parent=ctx) self.rememberStuff(context) # XXX: preprocessors? doc = self.docFactory.load(context) context.tag = inevow.IQ(doc).onePattern(name) return context
def test_bootstraps(self): """ L{LivePage._bootstraps} should return a list of 2-tuples of (initialization method, arguments) of methods to call in JavaScript. Specifically, it should invoke Divmod.bootstrap with the page's own URL, and Nevow.Athena.bootstrap with the name of the client-side Page class to instantiate and the URL to instantiate it with. """ SEG = "'" + '"' URI = "http://localhost/" + SEG req = FakeRequest(uri='/' + SEG, currentSegments=[SEG]) ctx = WovenContext() ctx.remember(req, IRequest) self.page.clientID = 'asdf' self.assertEqual( self.page._bootstraps(ctx), [ ( "Divmod.bootstrap", # Nevow's URL quoting rules are weird, but this is the URL # flattener's fault, not mine. Adjust to taste if that changes # (it won't) -glyph [u"http://localhost/'%22"]), ("Nevow.Athena.bootstrap", [u'Nevow.Athena.PageWidget', u'asdf']) ])
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)
def URLSerializer(original, context): """ Serialize the given L{URL}. Unicode path, query and fragment components are handled according to the IRI standard (RFC 3987). """ urlContext = WovenContext(parent=context, precompile=context.precompile, inURL=True) if original.scheme: # TODO: handle Unicode (see #2409) yield "%s://%s" % (original.scheme, original.netloc) for pathsegment in original._qpathlist: yield '/' yield serialize(pathsegment, urlContext) query = original._querylist if query: yield '?' first = True for key, value in query: if not first: # xhtml can't handle unescaped '&' if context.isAttrib is True: yield '&' else: yield '&' else: first = False yield serialize(key, urlContext) if value is not None: yield '=' yield serialize(value, urlContext) if original.fragment: yield "#" yield serialize(original.fragment, urlContext)
def doRendering(self, fragmentClass): """ Verify that the given fragment class will render without raising an exception. """ siteStore = Store() loginSystem = LoginSystem(store=siteStore) installOn(loginSystem, siteStore) p = Product(store=siteStore, types=["xmantissa.webadmin.LocalUserBrowser", "xmantissa.signup.SignupConfiguration"]) account = loginSystem.addAccount(u'testuser', u'localhost', None) p.installProductOn(account.avatars.open()) f = fragmentClass(None, u'testuser', account) p = LivePage( docFactory=stan( html[ head(render=directive('liveglue')), body(render=lambda ctx, data: f)])) f.setFragmentParent(p) ctx = WovenContext() req = FakeRequest() ctx.remember(req, IRequest) d = p.renderHTTP(ctx) def rendered(ign): p.action_close(None) d.addCallback(rendered) return d
def _render(self, page): """ Test helper which tries to render the given page. """ ctx = WovenContext() req = FakeRequest() ctx.remember(req, IRequest) return page.renderHTTP(ctx).addCallback(lambda ign: req.v)
def _render(self, fragment): """ Test helper which tries to render the given fragment. """ ctx = WovenContext() req = FakeRequest() ctx.remember(req, IRequest) return Page(docFactory=stan(fragment)).renderString(ctx)
def _render(self, resource): """ Test helper which tries to render the given resource. """ ctx = WovenContext() req = FakeRequest(headers={'host': self.hostname}) ctx.remember(req, IRequest) return req, resource.renderHTTP(ctx)
def _makeContext(): """ Create the request and context objects necessary for rendering a page. @return: A two-tuple of the created L{FakeRequest} and L{WovenContext}, with the former remembered in the latter. """ request = FakeRequest() context = WovenContext() context.remember(request, IRequest) return (request, context)
def test_renderReconnect(self): """ L{LivePage.renderHTTP} should render a JSON-encoded version of its clientID rather than a rendered version of its template when provided with a special __athena_reconnect__ parameter. """ req = FakeRequest(args={athena.ATHENA_RECONNECT: ["1"]}) ctx = WovenContext() ctx.remember(req, IRequest) string = self.page.renderHTTP(ctx) jsonifiedID = '"%s"' % (self.page.clientID, ) self.assertEqual(string, jsonifiedID)
def test_unsupportedBrowserPage(self): """ Test that unsupported browsers get told they're unsupported. """ ctx = WovenContext() page = athena.LivePage() req = FakeRequest() req.received_headers[ 'user-agent'] = "Mozilla/4.0 (compatible; MSIE 2.0; Windows NT 5.1)" ctx.remember(req, IRequest) d = renderPage(page, reqFactory=lambda: req) d.addCallback(self.assertEqual, flat.flatten(page.unsupportedBrowserLoader)) return d
def test_oldFlattenable(self): """ Flattening L{Element} instances with the old flatten function results in the flattened version of whatever their C{render} method returns. """ result = [] element = Element() element.docFactory = stan(['"&<>']) request = FakeRequest() context = WovenContext() context.remember(request) finished = oldFlatten(element, context, result.append, lambda ign: ign) finished.addCallback(lambda ign: "".join(result)) finished.addCallback(self.assertEqual, '"&<>') return finished
def test_oldFlattenableInAttribute(self): """ Flattening a L{Element} as the value of an attribute of a L{Tag} XML attribute escapes the element's flattened document. """ result = [] element = Element() element.docFactory = stan(['"&<>']) request = FakeRequest() context = WovenContext() context.remember(request) finished = oldFlatten(p(foo=element), context, result.append, lambda ign: ign) finished.addCallback(lambda ign: "".join(result)) finished.addCallback(self.assertEqual, '<p foo=""&<>"></p>') return finished
def _renderHead(self, result): """ Go through all the gyrations necessary to get the head contents produced by the page rendering process. """ site = ISiteURLGenerator(self.siteStore) t = tags.invisible() ctx = WovenContext(tag=t) req = FakeRequest() ctx.remember(req, IRequest) expected = [ th.head(req, site) for th in self.pageFactory._preferredThemes() ] head = result.render_head(ctx, None) return t, expected
def postForm(self, ctx, bindingName, args): """Accept a form post to the given bindingName. The bindingName can be dotted to indicate an attribute of this Configurable, eg addresses.0.changeEmail. The post arguments are given in args. Return a Resource which will be rendered in response. """ from formless import iformless from nevow.tags import invisible request = ctx.locate(inevow.IRequest) pathSegs = bindingName.split('.') configurable = self cf = ctx.locate(iformless.IConfigurableFactory) ## Get the first binding firstSeg = pathSegs.pop(0) binding = configurable.getBinding(ctx, firstSeg) ctx.remember(binding, IBinding) ctx.remember(configurable, IConfigurable) ## I don't think this works right now, it needs to be fixed. ## Most cases it won't be triggered, because we're just traversing a ## single binding name for seg in pathSegs: assert 1 == 0, "Sorry, this doesn't work right now" binding = configurable.getBinding(ctx, seg) child = self.boundTo if not isinstance(binding, GroupBinding): accessor = inevow.IContainer(configurable.boundTo, None) if accessor is None: child = getattr(configurable.boundTo, binding.name) else: child = accessor.child(ctx, binding.name) ## If it's a groupbinding, we don't do anything at all for this path segment ## This won't work right now. We need to push the previous configurable ## as the configurableFactory somehow and ask that for hte next binding ## we also need to support deferreds coming back from locateConfigurable assert 'black' is 'white', "Deferred support is pending" configurable = cf.locateConfigurable(ctx, child) ctx = WovenContext(ctx, invisible(key=seg)) ctx.remember(binding, IBinding) ctx.remember(configurable, IConfigurable) bindingProcessor = iformless.IInputProcessor(binding) rv = bindingProcessor.process(ctx, binding.boundTo, args) ctx.remember(rv, inevow.IHand) ctx.remember('%r success.' % bindingName, inevow.IStatusMessage) return rv
def precompile(stan, ctx=None): """Given the stan and the optional context, return a list of strings and Context instances, optimizing as much static content as possible into contiguous string runs. The Context instances will have Tag instances whose .children have also been precompiled. """ from nevow.context import WovenContext newctx = WovenContext(precompile=True) if ctx is not None: macroFactory = inevow.IMacroFactory(ctx, None) if macroFactory is not None: newctx.remember(macroFactory, inevow.IMacroFactory) doc = [] list(iterflatten(stan, newctx, doc.append)) return doc
def rend(self, ctx, data): # Unfortunately, we still need a context to make the rest of the # rendering process work. A goal should be to elimate this completely. context = WovenContext() if self.docFactory is None: raise MissingDocumentFactory(self) preprocessors = _getPreprocessors(self) doc = self.docFactory.load(context, preprocessors) context.remember(self, IData) context.remember(self, IRenderer) context.remember(self, IRendererFactory) context.tag = invisible[doc] return context
def FunctionSerializer(original, context, nocontextfun=FunctionSerializer_nocontext): if context.precompile: return WovenContext(tag=invisible(render=original)) else: data = convertToData(context.locate(IData), context) try: nocontext = nocontextfun(original) if nocontext is True: result = original(data) else: if nocontext is PASS_SELF: renderer = context.locate(IRenderer) result = original(renderer, context, data) else: result = original(context, data) except StopIteration: raise RuntimeError, "User function %r raised StopIteration." % original return serialize(result, context)
def test_pageJsClassDependencies(self): """ L{LivePage.render_liveglue} should include modules that the L{LivePage}'s jsClass depends on. """ self.page.jsClass = u'PythonTestSupport.Dependor.PageTest' freq = FakeRequest() self.page._becomeLive(url.URL.fromRequest(freq)) ctx = WovenContext(tag=tags.div()) ctx.remember(freq, IRequest) self.assertEqual(self.page.render_liveglue(ctx, None), ctx.tag) expectDependor = flat.flatten( self.page.getImportStan(u'PythonTestSupport.Dependor')) expectDependee = flat.flatten( self.page.getImportStan(u'PythonTestSupport.Dependee')) result = flat.flatten(ctx.tag, ctx) self.assertIn(expectDependor, result) self.assertIn(expectDependee, result)
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 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 test_oldFlattenableError(self): """ If the old flattener encounters an asynchronous Failure while flattening an L{IRenderable}, the returned L{Deferred} fires with the failure. """ result = Deferred() element = Element() element.docFactory = stan(result) request = FakeRequest() context = WovenContext() context.remember(request) accumulator = [] finished = oldFlatten(element, context, accumulator.append, lambda ign: ign) result.addErrback(lambda err: err.trap(RuntimeError)) finished = self.assertFailure(finished, RuntimeError) result.errback(RuntimeError("test error")) return finished
def process(self, context, boundTo, data, autoConfigure = True): """Knows how to process a dictionary of lists where the dictionary may contain a key with the same name as some of the arguments to the MethodBinding instance. """ typedValue = self.original.typedValue results = {} failures = {} if data.has_key('----'): ## ---- is the "direct object", the one argument you can specify using the command line without saying what the argument name is data[typedValue.arguments[0].name] = data['----'] del data['----'] for binding in typedValue.arguments: name = binding.name try: context = WovenContext(context, faketag) context.remember(binding, iformless.IBinding) results[name] = iformless.IInputProcessor(binding.typedValue).process(context, boundTo, data.get(name, [''])) except formless.InputError, e: results[name] = data.get(name, [''])[0] failures[name] = e.reason
def _ctxForRequest(request, slotData, renderFactory, inAttribute): """ Create a L{WovenContext} which can be used to by the backwards-compatibility support of L{IRenderer} and L{getFlattener} to continue rendering a response for the given request. """ ctx = WovenContext() ctx.isAttrib = inAttribute ctx.remember(None, IData) # Even though IData(ctx) can never return None, # remembering None here is somehow very important # for preventing a TypeError from happening when # ctx.locate(IData) is invoked, since it is # sometimes invoked from a codepath other than # __conform__. -exarkun ctx.remember(request, IRequest) for slotGroup in slotData: if slotGroup is not None: for k, v in slotGroup.items(): ctx.fillSlots(k, v) if renderFactory is not None: ctx.remember(_OldRendererFactory(renderFactory), IRendererFactory) return ctx
def URLSerializer(original, context): """ Serialize the given L{URL}. Unicode path, query and fragment components are handled according to the IRI standard (RFC 3987). """ def _maybeEncode(s): if isinstance(s, str): s = s.encode('utf-8') return s urlContext = WovenContext(parent=context, precompile=context.precompile, inURL=True) if original.scheme: # TODO: handle Unicode (see #2409) yield b"%s://%s" % (toBytes(original.scheme), toBytes(original.netloc)) for pathsegment in original._qpathlist: yield b'/' yield serialize(_maybeEncode(pathsegment), urlContext) query = original._querylist if query: yield b'?' first = True for key, value in query: if not first: # xhtml can't handle unescaped '&' if context.isAttrib is True: yield b'&' else: yield b'&' else: first = False yield serialize(_maybeEncode(key), urlContext) if value is not None: yield b'=' yield serialize(_maybeEncode(value), urlContext) if original.fragment: yield b"#" yield serialize(_maybeEncode(original.fragment), urlContext)
def _render(self, element): """ Put the given L{IRenderer} provider into an L{athena.LivePage} and render it. Return a Deferred which fires with the request object used which is an instance of L{nevow.testutil.FakeRequest}. """ p = LivePage(docFactory=stan(html[head( render=directive('liveglue')), body[invisible( render=lambda ctx, data: element)]])) element.setFragmentParent(p) ctx = WovenContext() req = FakeRequest() ctx.remember(req, IRequest) d = p.renderHTTP(ctx) def rendered(ign): p.action_close(None) return req d.addCallback(rendered) return d