Skip to content
32 changes: 26 additions & 6 deletions src/klein/_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
from ._app import (
ErrorMethods,
Klein,
KleinRenderable,
KleinRouteHandler,
RouteMetadata,
)
Expand Down Expand Up @@ -160,8 +159,27 @@ def __ne__(self, other: object) -> bool:
return NotImplemented
return not result

def render(self, request: IRequest) -> KleinRenderable:
# Stuff we need to know for the mapper.
def render(self, request: IRequest) -> int | bytes:
"""
Render the request based on the underlying L{Klein} application, in a
multi-step process:

1. convert twisted input request information into something legible
to werkzeug

2. bind that info (URL, method, query args, etc) into a request
mapper, and look up a werkzeug endpoint (i.e.: klein
C{@route}-decorated method) to invoke

3. invoke that endpoint, getting something renderable

4. render that thing

5. handle any errors in lookup or rendering with declared error
handlers

6. render the thing that the error handler returned
"""
try:
(
url_scheme,
Expand Down Expand Up @@ -232,8 +250,9 @@ def _execute() -> Deferred:
def process(r: object) -> Any:
"""
Recursively go through r and any child Resources until something
returns an IRenderable, then render it and let the result of that
bubble back up.
returns something renderable (L{IResource}, L{IRenderable},
L{bytes}, L{str}, or L{Iterable} of same), then render it and let
the result of that bubble back up.
"""
# isinstance() is faster than providedBy(), so this speeds up the
# very common case of returning pre-rendered results, at the cost
Expand Down Expand Up @@ -280,6 +299,7 @@ def processing_failed(
he = failure.value
assert isinstance(he, HTTPException)
request.setResponseCode(he.code)

resp = he.get_response({})

for header, value in resp.headers:
Expand Down Expand Up @@ -334,4 +354,4 @@ def write_response(
d.addCallback(write_response)
d.addErrback(log.err, _why="Unhandled Error writing response")

return server.NOT_DONE_YET # type: ignore[return-value]
return server.NOT_DONE_YET
6 changes: 3 additions & 3 deletions src/klein/test/test_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def getWrittenData(self) -> bytes:


def _render(
resource: KleinResource, request: IRequest, notifyFinish: bool = True
resource: KleinResource, request: Request, notifyFinish: bool = True
) -> Deferred:
result = resource.render(request)

Expand All @@ -144,10 +144,10 @@ def _render(
request.finish()
return succeed(None)

if result is not NOT_DONE_YET: # type: ignore[comparison-overlap]
if result is not NOT_DONE_YET:
raise AssertionError("unreachable") # pragma: no cover

if request.finished or not notifyFinish: # type: ignore[unreachable]
if request.finished or not notifyFinish:
return succeed(None)

return request.notifyFinish()
Expand Down
Loading