jamesremuscat / pyze

Unofficial Python client and API for Renault ZE
MIT License
112 stars 30 forks source link

Implement Asynchronous support #63

Closed epenet closed 4 years ago

epenet commented 4 years ago

For issue #60

jamesremuscat commented 4 years ago

@epenet Thanks for this work - having async support is a valuable addition.

Most of my experience is with Twisted rather than asyncio, and I'm having some trouble understanding how I'm supposed to use the async API.

I was naïvely expecting the following to work:

>>> from pyze.api import VehicleAsync
>>> v = VehicleAsync('VF1AGVYC059430480')
>>> import asyncio
>>> asyncio.run(v.battery_status())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.8/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "/mnt/shared/james/workspace/pyze/src/pyze/api/kamereon.py", line 624, in battery_status
    return await self._get('battery-status', 2)
  File "/mnt/shared/james/workspace/pyze/src/pyze/api/kamereon.py", line 594, in _get
    json = await self._request(
  File "/mnt/shared/james/workspace/pyze/src/pyze/api/kamereon.py", line 578, in _request
    'x-gigya-id_token': await self._kamereon._gigya.get_jwt_token(),
  File "/mnt/shared/james/workspace/pyze/src/pyze/api/gigya.py", line 220, in get_jwt_token
    async with self._websession.post(
  File "/mnt/shared/james/workspace/pyze/venv/lib/python3.8/site-packages/aiohttp/client.py", line 1012, in __aenter__
    self._resp = await self._coro
  File "/mnt/shared/james/workspace/pyze/venv/lib/python3.8/site-packages/aiohttp/client.py", line 426, in _request
    with timer:
  File "/mnt/shared/james/workspace/pyze/venv/lib/python3.8/site-packages/aiohttp/helpers.py", line 579, in __enter__
    raise RuntimeError('Timeout context manager should be used '
RuntimeError: Timeout context manager should be used inside a task

Please could you give me a basic incantation to get me started (possibly including it in the README)?

Architecturally, rather than maintaining synchronous and asynchronous versions of the same code, let's use the async ones internally and turn the sync ones into wrappers around those (possibly something like https://github.com/w1z2g3/syncasync could be useful?)

jamesremuscat commented 4 years ago

It also looks like some commits have leaked from some of your other PRs.

epenet commented 4 years ago

Because Async "bleeds" everywhere, it can be very difficult to make a "clean" PR, so yes it relies on PRs #61 and #62. I was also confident those two would get merged (not so sure about this one).

I did make a partial Async CLI just for testing, but it wasn't straightforward and because it involved duplicating every sync method I didn't want to do it until I was sure it was going to be used. I'll make sure the branch is available on my repository.

Dropping the Sync version of the API is likely to break a few projects out there, so I'd recommend keeping the two parallel versions of the same code. Regarding the CLI, it's a choice to make... Does the CLI keep using the Sync or does it move to the Async version? If the CLI uses the Async version, maybe the Sync version just dies down later down the road and it's up to the "other" projects to implement the Sync wrapper around the Async API.

epenet commented 4 years ago

A sample for the Async client is available on this branch with "status" and "login" calls migrated to Async.

epenet commented 4 years ago

New PR provided: #70