Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

curlify to support httpx:Response objects #34

Open
fenchu opened this issue Mar 28, 2023 · 0 comments
Open

curlify to support httpx:Response objects #34

fenchu opened this issue Mar 28, 2023 · 0 comments

Comments

@fenchu
Copy link

fenchu commented Mar 28, 2023

curlify==2.2.1
httpx==0.23.3

We are using curlify to print out curl requests when requests module requests fails, this has always worked great, but now I've moved my requests event hooks to httpx for http2 and asyncio support in our fastapi rest apis.

I believe httpx:Response is a bit different from requests.Response.

if I remove the curlify setting it works all fine

#!/usr/bin/env python3
import asyncio, curlify, httpx, json, textwrap

# we store each connection
connection = None

async def hook(response: httpx.Response) -> None:
    """ requests hook to see full rest requests+curl+response into connection_trace global, must not return anything """
    format_headers = lambda d: '\n'.join(f'{k}: {v}' for k, v in d.items())
    global connection
    out = ''
    await response.aread()
    print(f"response.{response}")
    request = response.request
    if not hasattr(request, 'body'):
        setattr(request, 'body', None)
    if not hasattr(response, 'reason'):
        setattr(response, 'reason', None)
    mycurl = curlify.to_curl(request)
    try:
        if response.text:
            out = json.dumps(json.loads(response.text), indent=2, sort_keys=True)
    except json.JSONDecodeError:
        out = response.text
    connection = textwrap.dedent('''
        ---------------- request ----------------
        {req.method} {req.url}
        {reqhdrs}

        {req.body}
        ------------------ curl ------------------
        {mycurl}
        ---------------- response ----------------
        {res.status_code} {res.reason} {res.url}
        {reshdrs}

        {out}
        -----------------------------------------
    ''').format(
        req=request,
        res=response,
        mycurl=mycurl,
        reqhdrs=format_headers(request.headers),
        reshdrs=format_headers(response.headers),
        out=out
    )

c = httpx.AsyncClient(event_hooks={'response': [hook]})
#c = httpx.AsyncClient()
r = asyncio.run(c.get("https://cat-fact.herokuapp.com/facts"))
print(connection)

I get this error:

python.exe .\bin\httpx-hook.py
response.<Response [200 OK]>
Traceback (most recent call last):
  File "C:\dist\work\trk-fullstack-test\bin\httpx-hook.py", line 50, in <module>
    r = asyncio.run(c.get("https://cat-fact.herokuapp.com/facts"))
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\dist\Python311\Lib\asyncio\runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "C:\dist\Python311\Lib\asyncio\runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\dist\Python311\Lib\asyncio\base_events.py", line 653, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "C:\dist\venvs\trk-fullstack-test\Lib\site-packages\httpx\_client.py", line 1757, in get
    return await self.request(
           ^^^^^^^^^^^^^^^^^^^
  File "C:\dist\venvs\trk-fullstack-test\Lib\site-packages\httpx\_client.py", line 1533, in request
    return await self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\dist\venvs\trk-fullstack-test\Lib\site-packages\httpx\_client.py", line 1620, in send
    response = await self._send_handling_auth(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\dist\venvs\trk-fullstack-test\Lib\site-packages\httpx\_client.py", line 1648, in _send_handling_auth
    response = await self._send_handling_redirects(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\dist\venvs\trk-fullstack-test\Lib\site-packages\httpx\_client.py", line 1706, in _send_handling_redirects
    raise exc
  File "C:\dist\venvs\trk-fullstack-test\Lib\site-packages\httpx\_client.py", line 1688, in _send_handling_redirects
    await hook(response)
  File "C:\dist\work\trk-fullstack-test\bin\httpx-hook.py", line 19, in hook
    mycurl = curlify.to_curl(request)
             ^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\dist\venvs\trk-fullstack-test\Lib\site-packages\curlify.py", line 44, in to_curl
    flat_parts.append(quote(v))
                      ^^^^^^^^
  File "C:\dist\Python311\Lib\shlex.py", line 329, in quote
    if _find_unsafe(s) is None:
       ^^^^^^^^^^^^^^^

removing the curlify it all works excellent: (it is a pubøic open api):

python.exe .\bin\httpx-hook.py
response.<Response [200 OK]>

---------------- request ----------------
GET https://cat-fact.herokuapp.com/facts
host: cat-fact.herokuapp.com
accept: */*
accept-encoding: gzip, deflate, br
connection: keep-alive
user-agent: python-httpx/0.23.3

None
---------------- response ----------------
200 None https://cat-fact.herokuapp.com/facts
server: Cowboy
connection: keep-alive
x-powered-by: Express
access-control-allow-origin: *
content-type: application/json; charset=utf-8
content-length: 1859
etag: W/"743-wddLBn/iA1pX11XPOeCdXfKM6GE"
set-cookie: connect.sid=s%3A1P6uo-hNorZRug0dYBtA0rUHUlf4DHeP.VyCKOnuAXShtRgYeKlO68tFuEmeXwfrr27QuqRtbuBE; Path=/; HttpOnly
date: Tue, 28 Mar 2023 14:53:52 GMT
via: 1.1 vegur

[
  {
    "__v": 0,
    "_id": "58e008800aac31001185ed07",
    "createdAt": "2018-03-06T21:20:03.505Z",
    "deleted": false,
    "source": "user",
    "status": {
      "sentCount": 1,
      "verified": true
    },
    "text": "Wikipedia has a recording of a cat meowing, because why not?",
    "type": "cat",
    "updatedAt": "2020-08-23T20:20:01.611Z",
    "used": false,
    "user": "58e007480aac31001185ecef"
  },
  {
    "__v": 0,
    "_id": "58e008630aac31001185ed01",
    "createdAt": "2018-02-07T21:20:02.903Z",
    "deleted": false,
    "source": "user",
    "status": {
      "sentCount": 1,
      "verified": true
    },
    "text": "When cats grimace, they are usually \"taste-scenting.\" They have an extra organ that, with some breathing control, allows the cats to taste-sense the air.",
    "type": "cat",
    "updatedAt": "2020-08-23T20:20:01.611Z",
    "used": false,
    "user": "58e007480aac31001185ecef"
  },
  {
    "__v": 0,
    "_id": "58e00a090aac31001185ed16",
    "createdAt": "2018-02-11T21:20:03.745Z",
    "deleted": false,
    "source": "user",
    "status": {
      "sentCount": 1,
      "verified": true
    },
    "text": "Cats make more than 100 different sounds whereas dogs make around 10.",
    "type": "cat",
    "updatedAt": "2020-08-23T20:20:01.611Z",
    "used": false,
    "user": "58e007480aac31001185ecef"
  },
  {
    "__v": 0,
    "_id": "58e009390aac31001185ed10",
    "createdAt": "2018-03-04T21:20:02.979Z",
    "deleted": false,
    "source": "user",
    "status": {
      "sentCount": 1,
      "verified": true
    },
    "text": "Most cats are lactose intolerant, and milk can cause painful stomach cramps and diarrhea. It's best to forego the milk and just give your cat the standard: clean, cool drinking water.",
    "type": "cat",
    "updatedAt": "2020-08-23T20:20:01.611Z",
    "used": false,
    "user": "58e007480aac31001185ecef"
  },
  {
    "__v": 0,
    "_id": "58e008780aac31001185ed05",
    "createdAt": "2018-03-29T20:20:03.844Z",
    "deleted": false,
    "source": "user",
    "status": {
      "sentCount": 1,
      "verified": true
    },
    "text": "Owning a cat can reduce the risk of stroke and heart attack by a third.",
    "type": "cat",
    "updatedAt": "2020-08-23T20:20:01.611Z",
    "used": false,
    "user": "58e007480aac31001185ecef"
  }
]
-----------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant