def test_template_numbers(self): """ Data returned from a plated method may include numeric types (integers, floats, and possibly longs), which although they are not normally serializable by twisted.web.template, will be converted by plating into their decimal representation. """ @page.routed( self.app.route("/"), tags.div( tags.span(slot("anInteger")), tags.i(slot("anFloat")), tags.b(slot("anLong")), ), ) def plateMe(result): return {"anInteger": 7, "anFloat": 3.2, "anLong": 0x10000000000000001} request, written = self.get(b"/") self.assertIn(b"<span>7</span>", written) self.assertIn(b"<i>3.2</i>", written) self.assertIn(b"<b>18446744073709551617</b>", written)
def test_widget_json_deferred(self): """ When L{Plating.widgeted} is applied as a decorator, and the result is serialized to JSON, it appears the same as the returned value despite the HTML-friendly wrapping described above. """ @page.routed(self.app.route("/"), tags.div(tags.div(slot("widget")), tags.div(slot("instance-widget")))) def rsrc(request): instance = InstanceWidget() return { "widget": deferredEnwidget.widget(a=3, b=4), "instance-widget": instance.deferredEnwidget.widget(5, 6) } request, written = self.get(b"/?json=1") self.assertEqual( json.loads(written.decode('utf-8')), { "widget": { "a": 3, "b": 4 }, "instance-widget": { "a": 5, "b": 6 }, "title": "default title unchanged" })
def test_template_numbers(self): """ Data returned from a plated method may include numeric types (integers, floats, and possibly longs), which although they are not normally serializable by twisted.web.template, will be converted by plating into their decimal representation. """ @page.routed( self.app.route("/"), tags.div( tags.span(slot("anInteger")), tags.i(slot("anFloat")), tags.b(slot("anLong")), ), ) def plateMe(result): return { "anInteger": 7, "anFloat": 3.2, "anLong": 0x10000000000000001 } request, written = self.get(b"/") self.assertIn(b"<span>7</span>", written) self.assertIn(b"<i>3.2</i>", written) self.assertIn(b"<b>18446744073709551617</b>", written)
def test_presentation_only_json(self): """ Slots marked as "presentation only" will not be reflected in the output. """ plating = Plating(tags=tags.span(slot("title")), presentation_slots={"title"}) @plating.routed(self.app.route("/"), tags.span(slot("data"))) def justJson(request): return {"title": "uninteresting", "data": "interesting"} request, written = self.get(b"/?json=1") self.assertEqual(json.loads(written.decode("utf-8")), {"data": "interesting"})
def test_serializedAttributeWithSlotWithSanitization(self): """ Like L{test_serializedAttributeWithSanitization} but with a slot. """ toss = [] self.checkAttributeSanitization( lambda value: toss.append(value) or slot("stuff"), lambda tag: tag.fillSlots(stuff=toss.pop()))
def test_serializedAttributeWithSlotWithSanitization(self): """ Like L{test_serializedAttributeWithSanitization} but with a slot. """ toss = [] self.checkAttributeSanitization( lambda value: toss.append(value) or slot("stuff"), lambda tag: tag.fillSlots(stuff=toss.pop()) )
def test_serializeDeferredSlots(self): """ Test that a slot with a deferred as its value will be flattened using the value from the deferred. """ t = tags.p(slot('test')) t.fillSlots(test=succeed(tags.em('four>'))) return self.assertFlattensTo(t, '<p><em>four></em></p>')
def test_serializeDeferredSlots(self): """ Test that a slot with a deferred as its value will be flattened using the value from the deferred. """ t = tags.p(slot("test")) t.fillSlots(test=succeed(tags.em("four>"))) return self.assertFlattensTo(t, b"<p><em>four></em></p>")
def test_widget_json(self): """ When L{Plating.widgeted} is applied as a decorator, and the result is serialized to JSON, it appears the same as the returned value despite the HTML-friendly wrapping described above. """ @page.routed(self.app.route("/"), tags.div(tags.div(slot("widget")), tags.div(slot("instance-widget")))) def rsrc(request): return {"widget": enwidget.widget(a=3, b=4), "instance-widget": InstanceWidget().enwidget.widget(5, 6)} request, written = self.get(b"/?json=1") self.assertEqual(json.loads(written.decode('utf-8')), {"widget": {"a": 3, "b": 4}, "instance-widget": {"a": 5, "b": 6}, "title": "default title unchanged"})
def test_serializeSlots(self): """ Test that flattening a slot will use the slot value from the tag. """ t1 = tags.p(slot("test")) t2 = t1.clone() t2.fillSlots(test="hello, world") self.assertFlatteningRaises(t1, UnfilledSlot) self.assertFlattensImmediately(t2, b"<p>hello, world</p>")
def test(missing): plating = Plating(tags=tags.span(slot(Plating.CONTENT))) @plating.routed(self.app.route("/"), tags.span(tags.span(render=missing))) def no(request): return {} self.get(b"/") [fe] = self.flushLoggedErrors(FlattenerError) self.assertIsInstance(fe.value.args[0], MissingRenderMethod)
class AppObj(object): app = Klein() def __init__(self, x): self.x = x @page.routed(app.route("/"), tags.span(slot('yeah'))) def plateInstance(self, request): return {"yeah": "test-instance-data-" + self.x}
def test_serializeSlots(self): """ Test that flattening a slot will use the slot value from the tag. """ t1 = tags.p(slot("test")) t2 = t1.clone() t2.fillSlots(test="hello, world") return gatherResults( [self.assertFlatteningRaises(t1, UnfilledSlot), self.assertFlattensTo(t2, "<p>hello, world</p>")] )
def test_widget_html(self): """ When L{Plating.widgeted} is applied as a decorator, it gives the decorated function a C{widget} attribute which is a version of the function with a modified return type that turns it into a renderable HTML sub-element that may fill a slot. """ @page.routed(self.app.route("/"), tags.div(tags.div(slot("widget")), tags.div(slot("instance-widget")))) def rsrc(request): return {"widget": enwidget.widget(a=3, b=4), "instance-widget": InstanceWidget().enwidget.widget(5, 6)} request, written = self.get(b"/") self.assertIn(b"<span>a: 3</span>", written) self.assertIn(b"<span>b: 4</span>", written) self.assertIn(b"<span>a: 5</span>", written) self.assertIn(b"<span>b: 6</span>", written)
def test_serializeSlots(self): """ Test that flattening a slot will use the slot value from the tag. """ t1 = tags.p(slot('test')) t2 = t1.clone() t2.fillSlots(test='hello, world') return gatherResults([ self.assertFlatteningRaises(t1, UnfilledSlot), self.assertFlattensTo(t2, '<p>hello, world</p>'), ])
def test_template_html(self): """ Rendering a L{Plating.routed} decorated route results in templated HTML. """ @page.routed(self.app.route("/"), tags.span(slot("ok"))) def plateMe(request): return {"ok": "test-data-present"} request, written = self.get(b"/") self.assertIn(b'<span>test-data-present</span>', written) self.assertIn(b'<title>default title unchanged</title>', written)
def test_prime_directive_return(self): """ Nothing within these Articles Of Federation shall authorize the United Federation of Planets to alter the return value of a callable by applying a decorator to it... """ exact_result = {"ok": "some nonsense value"} @page.routed(self.app.route("/"), tags.span(slot("ok"))) def plateMe(request): return exact_result self.assertIdentical(plateMe(None), exact_result)
def test_render_list(self): """ The C{:list} renderer suffix will render the slot named by the renderer as a list, filling each slot. """ @page.routed(self.app.route("/"), tags.ul(tags.li(slot("item"), render="subplating:list"))) def rsrc(request): return {"subplating": [1, 2, 3]} request, written = self.get(b"/") self.assertIn(b'<ul><li>1</li><li>2</li><li>3</li></ul>', written) self.assertIn(b'<title>default title unchanged</title>', written)
class SimpleFeedAggregation(object): application = Klein() common_page = Plating(tags=tags.html( tags.head(tags.title('Feed Aggregator 1.0')), tags.body(tags.div(slot(Plating.CONTENT))), )) def __init__(self, reactor, feed_urls): self._reactor = reactor self._feed_urls = feed_urls @defer.inlineCallbacks def retrieve_field(self, url): response = yield treq.get(url, timeout=30.0, reactor=self._reactor) if response.code != http.OK: fail_reason = http.RESPONSES[response.code] raise RuntimeError(f'Failed: {response.code} {fail_reason}') content = yield response.content() defer.returnValue(feedparser.parse(content)) @common_page.routed(application.route('/'), tags.div(render='feeds:list')(slot('item'))) def feeds(self, request): def render_feed(feed): feed_title = feed[u'feed'][u'title'] feed_link = feed[u'feed'][u'link'] return tags.table( tags.tr(tags.th(tags.a(feed_title, href=feed_link))))([ tags.tr( tags.td(tags.a(entry[u'title'], href=entry[u'link']))) for entry in feed[u'entries'] ]) return { u'feeds': [ self.retrieve_field(url).addCallback(render_feed) for url in self._feed_urls ] }
def test_widget_html(self): """ When L{Plating.widgeted} is applied as a decorator, it gives the decorated function a C{widget} attribute which is a version of the function with a modified return type that turns it into a renderable HTML sub-element that may fill a slot. """ @page.routed(self.app.route("/"), tags.div(tags.div(slot("widget")), tags.div(slot("instance-widget")))) def rsrc(request): return { "widget": enwidget.widget(a=3, b=4), "instance-widget": InstanceWidget().enwidget.widget(5, 6) } request, written = self.get(b"/") self.assertIn(b"<span>a: 3</span>", written) self.assertIn(b"<span>b: 4</span>", written) self.assertIn(b"<span>a: 5</span>", written) self.assertIn(b"<span>b: 6</span>", written)
class FeedAggregation(object): _retrieve = attr.ib() _urls = attr.ib() _app = Klein() _planting = Plating( tags=t.html( t.head(t.title('Feed Aggregator 2.0')), t.body(slot(Plating.CONTENT)) ) ) def resource(self): return self._app.resource() @_planting.routed( _app.route('/'), t.div(render='feeds:list')(slot('item')), ) def root(self, request): def convert(feed): return feed.as_json() if request.args.get(b'json') else feed.as_html() return {'feeds': [self._retrieve(url).addCallback(convert) for url in self._urls]}
class FeedAggregation(object): _retrieve = attr.ib() _urls = attr.ib() _app = Klein() _plating = Plating(tags=t.html(t.head(t.title("Feed Aggregator 2.0")), t.body(slot(Plating.CONTENT)))) def resource(self): return self._app.resource() @_plating.routed( _app.route("/"), t.div(render="feeds:list")(slot("item")), ) def root(self, request): def convert(feed): return feed.asJSON() if request.args.get( b"json") else feed.asHTML() return { "feeds": [self._retrieve(url).addCallback(convert) for url in self._urls] }
class SlowIncrementWebService(object): application = Klein() common_page = Plating(tags=tags.html( tags.head( tags.title(slot('title')), tags.style('#amount { font-weight: bold; }' '#message { font-style: italic; }')), tags.body(tags.div(slot(Plating.CONTENT))))) def __init__(self, reactor): self._reactor = reactor @common_page.routed(application.route('/<int:amount>'), tags.div( tags.span('Hello! Your new amount is: ', id='message'), tags.span(slot('new_amount'), id='amount'), )) def slow_increment(self, request, amount): slots = { 'title': 'Slow Increment', 'new_amount': amount + 1, } return task.deferLater(self._reactor, 1.0, lambda: slots)
def test_template_json(self): """ Rendering a L{Plating.routed} decorated route with a query parameter asking for JSON will yield JSON instead. """ @page.routed(self.app.route("/"), tags.span(slot("ok"))) def plateMe(request): return {"ok": "an-plating-test"} request, written = self.get(b"/?json=true") self.assertEqual( request.responseHeaders.getRawHeaders(b'content-type')[0], b'text/json; charset=utf-8' ) self.assertEquals({"ok": "an-plating-test", "title": "default title unchanged"}, json.loads(written.decode('utf-8')))
def test_template_json(self): """ Rendering a L{Plating.routed} decorated route with a query parameter asking for JSON will yield JSON instead. """ @page.routed(self.app.route("/"), tags.span(slot("ok"))) def plateMe(request): return {"ok": "an-plating-test"} request, written = self.get(b"/?json=true") self.assertEqual( request.responseHeaders.getRawHeaders(b'content-type')[0], b'text/json; charset=utf-8') self.assertEquals( { "ok": "an-plating-test", "title": "default title unchanged" }, json.loads(written.decode('utf-8')))
def test_prime_directive_arguments(self): """ ... or shall require the function to modify its signature under these Articles Of Federation. """ @page.routed(self.app.route("/"), tags.span(slot("ok"))) def plateMe(request, one, two, three): return (one, two, three) exact_one = {"one": "and"} exact_two = {"two": "and"} exact_three = {"three": "and"} result_one, result_two, result_three = plateMe( None, exact_one, exact_two, three=exact_three ) self.assertIdentical(result_one, exact_one) self.assertIdentical(result_two, exact_two) self.assertIdentical(result_three, exact_three)
def test_prime_directive_arguments(self): """ ... or shall require the function to modify its signature under these Articles Of Federation. """ @page.routed(self.app.route("/"), tags.span(slot("ok"))) def plateMe(request, one, two, three): return (one, two, three) exact_one = {"one": "and"} exact_two = {"two": "and"} exact_three = {"three": "and"} result_one, result_two, result_three = plateMe(None, exact_one, exact_two, three=exact_three) self.assertIdentical(result_one, exact_one) self.assertIdentical(result_two, exact_two) self.assertIdentical(result_three, exact_three)
def test_template_json_contains_deferred(self): """ Rendering a L{Plating.routed} decorated route with a query parameter asking for JSON waits until the L{Deferred}s returned by the route have fired. """ @page.routed(self.app.route("/"), tags.span(slot("ok"))) def plateMe(request): return {"ok": succeed("an-plating-test")} request, written = self.get(b"/?json=true") self.assertEqual( request.responseHeaders.getRawHeaders(b"content-type")[0], b"text/json; charset=utf-8", ) self.assertEquals( { "ok": "an-plating-test", "title": "default title unchanged" }, json.loads(written.decode("utf-8")), )
from klein import Plating from twisted.web.template import tags, slot from twisted.web.error import FlattenerError, MissingRenderMethod from klein.test.test_resource import requestMock, _render from klein.test.util import TestCase from klein import Klein page = Plating( defaults={ "title": "default title unchanged", Plating.CONTENT: "NEVER MIND THE CONTENT", }, tags=tags.html( tags.head(tags.title(slot("title"))), tags.body( tags.h1(slot("title")), tags.div(slot(Plating.CONTENT), Class="content") ) ), ) element = Plating( defaults={ "a": "NO VALUE FOR A", "b": "NO VALUE FOR B", }, tags=tags.div(tags.span("a: ", slot("a")), tags.span("b: ", slot("b"))),
from twisted.trial.unittest import (SynchronousTestCase, TestCase as AsynchronousTestCase) from twisted.web.error import FlattenerError, MissingRenderMethod from twisted.web.template import slot, tags from .test_resource import _render, requestMock from .. import Klein, Plating from .._plating import ATOM_TYPES, PlatedElement, resolveDeferredObjects page = Plating( defaults={ "title": "default title unchanged", Plating.CONTENT: "NEVER MIND THE CONTENT", }, tags=tags.html( tags.head(tags.title(slot("title"))), tags.body( tags.h1(slot("title")), tags.div(slot(Plating.CONTENT), Class="content"), ), ), ) element = Plating( defaults={ "a": "NO VALUE FOR A", "b": "NO VALUE FOR B", }, tags=tags.div( tags.span("a: ", slot("a")), tags.span("b: ", slot("b")),
from klein.storage.memory import MemorySessionStore app = Klein() sessions = MemorySessionStore() requirer = Requirer() @requirer.prerequisite([ISession]) def procurer(request): return SessionProcurer(sessions).procureSession(request) style = Plating(tags=tags.html( tags.head(tags.title("yay")), tags.body(tags.div(slot(Plating.CONTENT)))) ) @style.routed( requirer.require( app.route("/", methods=["POST"]), foo=Field.integer(minimum=3, maximum=10), bar=Field.text(), ), tags.h1('u did it: ', slot("an-form-arg")) ) def postHandler(foo, bar): return {"an-form-arg": foo} @requirer.require( style.routed( app.route("/", methods=["GET"]),
) from twisted.web.error import FlattenerError, MissingRenderMethod from twisted.web.template import slot, tags from .test_resource import _render, requestMock from .. import Klein, Plating from .._plating import ATOM_TYPES, PlatedElement, resolveDeferredObjects page = Plating( defaults={ "title": "default title unchanged", Plating.CONTENT: "NEVER MIND THE CONTENT", }, tags=tags.html( tags.head(tags.title(slot("title"))), tags.body( tags.h1(slot("title")), tags.div(slot(Plating.CONTENT), Class="content"), ), ), ) element = Plating( defaults={ "a": "NO VALUE FOR A", "b": "NO VALUE FOR B", }, tags=tags.div( tags.span("a: ", slot("a")), tags.span("b: ", slot("b")),
# Cobble together a deterministic random function using a string as a seed. from random import Random from hashlib import sha256 from struct import unpack def random_from_string(string): return Random(unpack("!I", sha256(string.encode("utf-8")).digest()[:4])[0]) from twisted.web.template import tags, slot from klein import Klein, Plating app = Klein() myStyle = Plating(tags=tags.html( tags.head(tags.title(slot("pageTitle"))), tags.body(tags.h1(slot("pageTitle"), Class="titleHeading"), tags.div(slot(Plating.CONTENT)))), defaults={"pageTitle": "Places & Foods"}) @myStyle.routed( app.route("/"), tags.div( tags.h2("Sample Places:"), tags.ul([ tags.li(tags.a(href=["/places/", place])(place)) for place in ["new york", "san francisco", "shanghai"] ]), tags.h2("Sample Foods:"), tags.ul([
#!/usr/bin/python3 # -*- coding: utf-8 -*- from klein import run, route from twisted.web.template import tags, slot from klein import Klein, Plating from input_handler import handle_input app = Klein() myStyle = Plating( tags=tags.html( tags.head(tags.title(slot("pageTitle"))), tags.body(tags.h1(slot("pageTitle"), Class="titleHeading"), tags.div(slot(Plating.CONTENT))) ) ) @myStyle.routed( app.route("/input/"), tags.div()) def input(request): return {"r":['Hello, world!']} if __name__ == '__main__': app.run("localhost", 8080)
from random import Random from hashlib import sha256 from struct import unpack def random_from_string(string): return Random( unpack("!I", sha256(string.encode("utf-8")).digest()[:4])[0] ) from twisted.web.template import tags, slot from klein import Klein, Plating app = Klein() myStyle = Plating( tags=tags.html( tags.head(tags.title(slot("pageTitle"))), tags.body(tags.h1(slot("pageTitle"), Class="titleHeading"), tags.div(slot(Plating.CONTENT))) ), defaults={"pageTitle": "Places & Foods"} ) @myStyle.routed( app.route("/"), tags.div( tags.h2("Sample Places:"), tags.ul([tags.li(tags.a(href=["/places/", place])(place)) for place in ["new york", "san francisco", "shanghai"]]), tags.h2("Sample Foods:"), tags.ul([tags.li(tags.a(href=["/foods/", food])(food)) for food in ["hamburgers", "cheeseburgers", "hot dogs"]]),
from klein.storage.memory import MemorySessionStore app = Klein() sessions = MemorySessionStore() requirer = Requirer() @requirer.prerequisite([ISession]) def procurer(request): return SessionProcurer(sessions).procureSession(request) style = Plating(tags=tags.html(tags.head(tags.title("yay")), tags.body(tags.div(slot(Plating.CONTENT))))) @requirer.require( style.routed( app.route("/", methods=["POST"]), tags.h1("u did it: ", slot("an-form-arg")), ), foo=Field.number(minimum=3, maximum=10), bar=Field.text(), ) def postHandler(foo, bar): return {"an-form-arg": foo} @requirer.require(
def insertSlot(value: str) -> Flattenable: toss.append(value) return slot("stuff")