Skip to content

Commit

Permalink
feat(wsgi): actually add new files
Browse files Browse the repository at this point in the history
  • Loading branch information
vytas7 committed Aug 28, 2024
1 parent ac8ff4b commit c3a3eef
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
14 changes: 14 additions & 0 deletions falcon_sync/common/adapter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import asyncio
import functools


class BaseAdapter:
def __init__(self, executor=None):
self._executor = executor

async def run_in_executor(self, func, *args, **kwargs):
loop = asyncio.get_running_loop()
if kwargs:
func = functools.partial(func, *args, **kwargs)
args = []
return await loop.run_in_executor(self._executor, func, *args)
30 changes: 30 additions & 0 deletions falcon_sync/wsgi/response.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import falcon.asgi

from falcon_sync.common import proxy


class ResponseProxy(falcon.asgi.Response, metaclass=proxy.ProxyMeta):
_PROXY_INHERIT = frozenset({})

def __init__(self, resp, adapter):
self._response = resp
self._adapter = adapter

# TODO(vytas): Safer to proxy these via private properties as well.
self._media = resp._media
self._media_rendered = resp._media_rendered

@property
def stream(self):
return self._response.stream

@stream.setter
def stream(self, value):
self._response.stream = self._adapter.wrap_async_gen(value)

def set_stream(self, stream, content_length):
self.stream = stream
self.content_length = content_length

async def render_body(self):
return self._adapter.run_in_executor(self._response.render_body)
50 changes: 50 additions & 0 deletions tests/wsgi/test_stream.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import falcon
import falcon.testing

from falcon_sync.wsgi.adapter import Adapter


class WordsResource:
def __init__(self):
self._data = {}

async def on_put(self, req, resp, itemid):
data = await req.stream.read()
self._data[itemid] = data.strip().decode()
resp.status = falcon.HTTP_NO_CONTENT

async def on_get(self, req, resp, itemid):
async def word_generator():
for word in words:
yield word.encode() + b' '

sentence = self._data.get(itemid)
if sentence is None:
raise falcon.HTTPNotFound
words = sentence.split()
resp.content_length = sum(len(word) + 1 for word in words)
resp.content_type = falcon.MEDIA_TEXT
resp.stream = word_generator()


def test_async_generator():
pangram = 'The quick brown fox jumps over the lazy dog'
resource = WordsResource()

app = falcon.App()

with Adapter() as adapter:
wrapped = adapter.wrap_resource(resource)
app.add_route('/words/{itemid}', wrapped)

result1 = falcon.testing.simulate_put(
app, '/words/s1337', body=pangram
)
assert result1.status_code == 204

result2 = falcon.testing.simulate_get(app, '/words/s_1337')
assert result2.status_code == 404

result3 = falcon.testing.simulate_get(app, '/words/s1337')
assert result3.status_code == 200
assert result3.text == pangram + ' '

0 comments on commit c3a3eef

Please sign in to comment.