-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add full asyncio mode to bravado-asyncio
- Loading branch information
Showing
9 changed files
with
347 additions
and
92 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from enum import Enum | ||
from typing import NamedTuple | ||
from typing import Optional | ||
|
||
import aiohttp | ||
|
||
|
||
class RunMode(Enum): | ||
THREAD = 'thread' | ||
FULL_ASYNCIO = 'full_asyncio' | ||
|
||
|
||
AsyncioResponse = NamedTuple( | ||
'AsyncioResponse', [ | ||
('response', aiohttp.ClientResponse), | ||
('remaining_timeout', Optional[float]), | ||
] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import asyncio | ||
import concurrent.futures | ||
import time | ||
from typing import Optional | ||
|
||
from bravado.http_future import FutureAdapter as BaseFutureAdapter | ||
|
||
from .definitions import AsyncioResponse | ||
|
||
|
||
class FutureAdapter(BaseFutureAdapter): | ||
"""FutureAdapter that will be used when run_mode is THREAD. The result method is | ||
a normal Python function, and we expect future to be from the concurrent.futures module.""" | ||
|
||
timeout_errors = (concurrent.futures.TimeoutError,) | ||
|
||
def __init__(self, future: concurrent.futures.Future) -> None: | ||
self.future = future | ||
|
||
def result(self, timeout: Optional[float]=None) -> AsyncioResponse: | ||
start = time.monotonic() | ||
response = self.future.result(timeout) | ||
time_elapsed = time.monotonic() - start | ||
remaining_timeout = timeout - time_elapsed if timeout else None | ||
|
||
return AsyncioResponse(response=response, remaining_timeout=remaining_timeout) | ||
|
||
|
||
class AsyncioFutureAdapter(BaseFutureAdapter): | ||
"""FutureAdapter that will be used when run_mode is FULL_ASYNCIO. The result method is | ||
a coroutine, and we expect future to be awaitable.""" | ||
|
||
timeout_errors = (asyncio.TimeoutError,) | ||
|
||
def __init__(self, future: asyncio.Future) -> None: | ||
self.future = future | ||
|
||
async def result(self, timeout: Optional[float]=None) -> AsyncioResponse: | ||
start = time.monotonic() | ||
response = await asyncio.wait_for(self.future, timeout=timeout) | ||
time_elapsed = time.monotonic() - start | ||
remaining_timeout = timeout - time_elapsed if timeout else None | ||
|
||
return AsyncioResponse(response=response, remaining_timeout=remaining_timeout) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import asyncio | ||
from typing import TypeVar | ||
|
||
from bravado_core.response import IncomingResponse | ||
|
||
from .definitions import AsyncioResponse | ||
|
||
|
||
T = TypeVar('T') | ||
|
||
|
||
class AioHTTPResponseAdapter(IncomingResponse): | ||
"""Wraps a aiohttp Response object to provide a bravado-like interface | ||
to the response innards.""" | ||
|
||
def __init__(self, loop: asyncio.AbstractEventLoop) -> None: | ||
self._loop = loop | ||
|
||
def __call__(self: T, response: AsyncioResponse) -> T: | ||
self._delegate = response.response | ||
self._remaining_timeout = response.remaining_timeout | ||
return self | ||
|
||
@property | ||
def status_code(self): | ||
return self._delegate.status | ||
|
||
@property | ||
def text(self): | ||
future = asyncio.run_coroutine_threadsafe(self._delegate.text(), self._loop) | ||
return future.result(self._remaining_timeout) | ||
|
||
@property | ||
def raw_bytes(self): | ||
future = asyncio.run_coroutine_threadsafe(self._delegate.read(), self._loop) | ||
return future.result(self._remaining_timeout) | ||
|
||
@property | ||
def reason(self): | ||
return self._delegate.reason | ||
|
||
@property | ||
def headers(self): | ||
return self._delegate.headers | ||
|
||
def json(self, **_): | ||
future = asyncio.run_coroutine_threadsafe(self._delegate.json(), self._loop) | ||
return future.result(self._remaining_timeout) | ||
|
||
|
||
class AsyncioHTTPResponseAdapter(AioHTTPResponseAdapter): | ||
"""Wraps a aiohttp Response object to provide a bravado-like interface to the response innards. | ||
Methods are coroutines if they call coroutines themselves and need to be awaited.""" | ||
|
||
@property | ||
async def text(self): | ||
return await asyncio.wait_for(self._delegate.text(), timeout=self._remaining_timeout, loop=self._loop) | ||
|
||
@property | ||
async def raw_bytes(self): | ||
return await asyncio.wait_for(self._delegate.read(), timeout=self._remaining_timeout, loop=self._loop) | ||
|
||
async def json(self, **_): | ||
return await asyncio.wait_for(self._delegate.json(), timeout=self._remaining_timeout, loop=self._loop) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
"""Module for creating a separate thread with an asyncio event loop running inside it.""" | ||
import asyncio | ||
import threading | ||
from typing import Optional | ||
|
||
|
||
# module variable holding a reference to the event loop | ||
event_loop: Optional[asyncio.AbstractEventLoop] = None | ||
|
||
|
||
def run_event_loop(loop: asyncio.AbstractEventLoop) -> None: | ||
asyncio.set_event_loop(loop) | ||
loop.run_forever() | ||
|
||
|
||
def get_thread_loop() -> asyncio.AbstractEventLoop: | ||
global event_loop | ||
if event_loop is None: | ||
event_loop = asyncio.new_event_loop() | ||
thread = threading.Thread(target=run_event_loop, args=(event_loop,), daemon=True) | ||
thread.start() | ||
return event_loop |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
aiobravado | ||
bravado-core>=4.11.0 | ||
bravado>=9.2.0 | ||
coverage | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.