Unified async/sync interface

Demian Brecht demianbrecht at gmail.com
Sat Mar 31 21:44:59 EDT 2018


I might be entirely off my face, but figured I'd ask anyways given I
haven't figured out a clean solution to this problem myself yet:

I'm trying to write a REST API client that supports both async and
synchronous HTTP transports (initially requests and aiohttp). So far,
I've tried a few approaches with `async def` but, of course, you always
run into the issue with the top level API that should either be async
or not, but can't be redefined on the fly (AFAICT). I'm also trying to
limit code duplication. I know I could write async and sync versions of
each method and then instantiate through composition based on the
transport layer but I'd like to avoid that if possible. As an
simplified example of what I'm after:

import requests
import aiohttp

class SyncTransport:
  def get(self, url):
     return requests.get(url)

class AsyncTransport:
  def __init__(self, loop=None):
    self.loop = loop

  async def get(self, url):
    [...preamble...]
    return await response.text()

class MyAPIClient:
  def __init__(self, transport=SyncTransport):
    self.transport = transport()

  # biggest issue here atm, not being able to dynamically swap the
  # method definition to async
  def get_something(self):
    if isinstance(self.transport, AsyncTransport):
      data = await self.transport.get('https://example.com')
    else:
      data = self.transport.get('https://example.com')
    return json.loads(data)

# intended synchronous usage
client = MyAPIClient()
data = client.get_something()

# intended async usage
import asyncio
client =
MyAPIClient(transport=AysncTransport(loop=asyncio.get_event_loop())

async def get_something():
  data = await client.get_something()

loop = asyncio.get_event_loop()
loop.run_until_complete(get_something())


Is this perhaps possible through asyncio.coroutine decorators
(admittedly, I haven't looked yet, I've had async/await blinders on)?
Are there any projects that anyone's aware of that does anything
similar that I could use as an example?

The overall point of what I'm trying to achieve here is to write a
client that's supported from 2.7 to 3.x and supports /either/
synchronous or asynchronous transports (not both at the same time).

TIA
Demian
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: This is a digitally signed message part
URL: <http://mail.python.org/pipermail/python-list/attachments/20180331/54914ec4/attachment.sig>


More information about the Python-list mailing list