uplink icon indicating copy to clipboard operation
uplink copied to clipboard

async vs sync and list as query parameter

Open chassing opened this issue 6 years ago • 0 comments

Hi folks,

first of all thanks for this great python library, awesome work! I think I found a glitch between sync and async support in regards of query parameter handling.

Describe the bug So far as I understand I can use lists as query params too and it'll generate urls like /?a=1&a=2 but it looks like there is a difference between sync (requests) and async (aiohttp).

To Reproduce

import asyncio
import os
import sys

from uplink import AiohttpClient, Consumer, Query, get

BASE_URL = "http://httpbin.org/"


class HttpBin(Consumer):
    """Just a stub."""

    @get("get")
    def get(self, names: Query("vm.names")):
        pass


def test_sync():
    httpbin = HttpBin(base_url=BASE_URL)
    resp = httpbin.get(names=["foo", "bar"])
    print(resp.json()["args"])


async def test_async():
    httpbin = HttpBin(base_url=BASE_URL, client=AiohttpClient())
    resp = await httpbin.get(names=["foo", "bar"])
    print((await resp.json())["args"])


if __name__ == "__main__":
    test_sync()

    loop = asyncio.get_event_loop()
    loop.run_until_complete(test_async())
    sys.exit(0)

Expected behavior test_sync prints {'vm.names': ['foo', 'bar']}

but test_async

Traceback (most recent call last):
  File "uplink-debug.py", line 39, in <module>
    loop.run_until_complete(test_async())
  File "/home/user/.env/lib/python3.6/asyncio/base_events.py", line 484, in run_until_complete
    return future.result()
  File "uplink-debug.py", line 31, in test_async
    resp = await httpbin.get(names=["foo", "bar"])
  File "/home/user/.env/lib/python3.6/site-packages/uplink/clients/io/asyncio_strategy.py", line 38, in execute
    response = yield from executable.execute()
  File "/home/user/.env/lib/python3.6/site-packages/uplink/clients/io/asyncio_strategy.py", line 20, in invoke
    response = yield from callback.on_failure(type(error), error, tb)
  File "/home/user/.env/lib/python3.6/site-packages/uplink/clients/io/asyncio_strategy.py", line 20, in invoke
    response = yield from callback.on_failure(type(error), error, tb)
  File "/home/user/.env/lib/python3.6/site-packages/uplink/clients/io/execution.py", line 108, in on_failure
    return self._io.fail(exc_type, exc_val, exc_tb)
  File "/home/user/.env/lib/python3.6/site-packages/uplink/clients/io/interfaces.py", line 303, in fail
    compat.reraise(exc_type, exc_val, exc_tb)
  File "/home/user/.env/lib/python3.6/site-packages/six.py", line 693, in reraise
    raise value
  File "/home/user/.env/lib/python3.6/site-packages/uplink/clients/io/asyncio_strategy.py", line 17, in invoke
    response = yield from func(*args, **kwargs)
  File "/home/user/.env/lib/python3.6/site-packages/uplink/hooks.py", line 109, in handle_exception
    compat.reraise(exc_type, exc_val, exc_tb)
  File "/home/user/.env/lib/python3.6/site-packages/six.py", line 693, in reraise
    raise value
  File "/home/user/.env/lib/python3.6/site-packages/uplink/clients/io/asyncio_strategy.py", line 17, in invoke
    response = yield from func(*args, **kwargs)
  File "/home/user/.env/lib/python3.6/site-packages/uplink/clients/aiohttp_.py", line 137, in send
    response = yield from session.request(method, url, **extras)
  File "/home/user/.env/lib/python3.6/site-packages/aiohttp/client.py", line 473, in _request
    ssl=ssl, proxy_headers=proxy_headers, traces=traces)
  File "/home/user/.env/lib/python3.6/site-packages/aiohttp/client_reqrep.py", line 263, in __init__
    url2 = url.with_query(params)
  File "/home/user/.env/lib/python3.6/site-packages/yarl/__init__.py", line 885, in with_query
    new_query = self._get_str_query(*args, **kwargs)
  File "/home/user/.env/lib/python3.6/site-packages/yarl/__init__.py", line 849, in _get_str_query
    quoter(k) + "=" + quoter(self._query_var(v)) for k, v in query.items()
  File "/home/user/.env/lib/python3.6/site-packages/yarl/__init__.py", line 849, in <genexpr>
    quoter(k) + "=" + quoter(self._query_var(v)) for k, v in query.items()
  File "/home/user/.env/lib/python3.6/site-packages/yarl/__init__.py", line 827, in _query_var
    "of type {}".format(v, type(v))
TypeError: Invalid variable type: value should be str or int, got ['foo', 'bar'] of type <class 'list'>

looks like yarl (aiohttp) doesn't support lists, aiohttp documentation mention you have to use MultiDict but uplink doesn't support MultiDict :(

cheers, chris

chassing avatar Sep 25 '19 06:09 chassing