Search code examples
pythonpython-asyncioaiohttp

aiohttp unclosed client session


Relating to my question posted earlier how to post aiohttp authenticated request? [duplicate] which was answered in Send user credentials in aiohttp request, I modified the code to below and managed to get the result from get_all_balances(), however I would have the error below prior to getting the result:

Unclosed client session client_session: <aiohttp.client.ClientSession object at 0x0000019AD3E12790> Unclosed connector connections: ['[(<aiohttp.client_proto.ResponseHandler object at 0x0000019AD3E09470>, 613500.125)]'] connector: <aiohttp.connector.TCPConnector object at 0x0000019AD34A93D0>

As far as I can see, the function is called with async with and the result is with await, my understanding is that the connection would be closed upon the result, so why is it that it's giving me an unclosed client session error?

import asyncio
import aiohttp
import json


base_url = 'https://api.luno.com'
lapikey = ''
lapisecret = ''


async def do(method, path, req=None, auth=False):
    args = {}
    params = None
    if req:
        try:
            params = json.loads(json.dumps(req))
        except Exception:
            params = None
    if params:
        args = dict(params=params)
    url = make_url(path, params)
    if auth:
        args['auth'] = aiohttp.BasicAuth(lapikey, lapisecret)
    async with aiohttp.ClientSession().request(method, url, **args) as res:
        try:
            return await res.json()
        except Exception as e:
            return e

def make_url(path, params):
    if params:
        for k, v in params.items():
            path = path.replace('{' + k + '}', str(v))
    return base_url + '/' + path.lstrip('/')

async def get_all_balances():
    return await do('GET', '/api/1/balance', auth=True)


print(asyncio.run(get_all_balances()))

I have read other similar questions on aiohttp unclosed client session, as far as I can tell my code has already implemented all the requisite async with and await keywords to properly close the client session after the request, what is wrong?


Solution

  • Try to first make an aiohttp Session() and afterwards do a request:

    import asyncio
    import aiohttp
    import json
    
    
    base_url = 'https://api.luno.com'
    lapikey = ''
    lapisecret = ''
    
    
    async def do(method, path, req=None, auth=False):
        args = {}
        params = None
        if req:
            try:
                params = json.loads(json.dumps(req))
            except Exception:
                params = None
        if params:
            args = dict(params=params)
        url = make_url(path, params)
        if auth:
            args['auth'] = aiohttp.BasicAuth(lapikey, lapisecret)
    
        async with aiohttp.ClientSession() as session:                # <--- create session here
            async with session.request(method, url, **args) as res:   # <-- and then do a request
                try:
                    return await res.json()
                except Exception as e:
                    return e
    
    def make_url(path, params):
        if params:
            for k, v in params.items():
                path = path.replace('{' + k + '}', str(v))
        return base_url + '/' + path.lstrip('/')
    
    async def get_all_balances():
        return await do('GET', '/api/1/balance', auth=True)
    
    
    print(asyncio.run(get_all_balances()))