Search code examples
pythonpython-asynciohttpx

Why am I getting python-httpx Unclosed object warning?


What I am doing wrong? Is there a fix? I'm new to async programming; it's very confusing.

# myFile.py
import httpx
async def ping_api():
    async with httpx.AsyncClient() as client:
        sleep(1)
        print('right after with')
        sleep(1)
        print('before await')
        sleep(1)
        response = await client.get(url, params=params)
        sleep(1)
        print('after await')
        sleep(1)
        data = response.json() # what's wrong here?
        sleep(1)
        print('after json')
        sleep(1)

    return data



# myFastAPI.py
from myFile import ping_api
@app...
async def main():
    data = await ping_api()

 

Resulting error:

before await
after await
C:\Users\foo\grok\site-packages\httpx\_client.py:1772: UserWarning: Unclosed <authlib.integrations.httpx_client.oauth2_client.AsyncOAuth2Client object at 0x0000021F318EC5E0>. See https://www.python-httpx.org/async/#opening-and-closing-clients for details.
warnings.warn(
after json

Shouldn't the context manager automatically close the connection? Is this a bug in the library or am I missing something? Is this response.json() the cause or is the problem elsewhere but just happens to 'print' at this point?

https://github.com/encode/httpx/issues/1332


Solution

  • Found cause: The issue was actually my usage of another library(tda-api). Found answer Here; "Do not attempt to use more than one Client object per token file, as this will likely cause issues with the underlying OAuth2 session management". My mistake was causing the 'printing' of the error in function calls that had no obvious relationship to me (e.g. datetime.combine(), response.json()). Instead of invoking the creation of the client object within the function, I created it outside and passed the client object as a parameter argument to my various async def functions.

    The error does not occur in sync def functions because it does not yield the thread to the event loop at any point before returning. This means there are no concurrent Client objects invoked at the same time. Thus, the 1:1 Client object:token file ratio is not violated in the synchronous case and creating the Client object inside the function is not an issue.