¿Cómo pasar parámetros adicionales a handle_client coroutine?

La forma recomendada de usar asyncio para un servidor de socket es:

import asyncio async def handle_client(reader, writer): request = (await reader.read(100)).decode() response = "Data received." writer.write(response.encode()) async def main(): loop.create_task(asyncio.start_server(handle_client, 'localhost', 15555)) loop = asyncio.get_event_loop() loop.create_task(main()) loop.run_forever() 

Esto funciona bien, pero ahora necesito recibir una solicitud de cliente adecuada y luego usar la biblioteca aiohttp para obtener datos de una API de terceros.

Esto requiere crear una variable de sesión de la siguiente manera:

 from aiohttp import ClientSession session = ClientSession() 

Pero esto también debería estar dentro de una propia coroutine, así que la pondré dentro de main:

 async def main(): session = ClientSession() loop.create_task(asyncio.start_server(handle_client, '', 55555)) 

Ahora necesito pasar la variable de sesión al aiohttp get coroutine para obtener los datos de la API del rest:

 async with session.get(url, params=params) as r: try: return await r.json(content_type='application/json') except aiohttp.client_exceptions.ClientResponseError: .... 

Mi pregunta es ¿cómo puedo pasar la variable de sesión a handle_client coroutine, si insiste en tener solo lector, parámetros de escritor y variables globales que no me ayudan porque las sesiones deben existir dentro de coroutines?

Puedes usar una función temporal o lambda:

 async def main(): session = aiohttp.ClientSession() await asyncio.start_server(lambda r, w: handle_client(r, w, session), '', 55555) 

Esto funciona porque, aunque la lambda no es técnicamente una coroutina, se comporta como una, es una llamada que devuelve un objeto coroutine cuando se invoca.

Para progtwigs más grandes, es posible que prefiera un enfoque basado en clase con una clase que encapsule el estado compartido por varios clientes sin tener que pasarlo de coroutine a coroutine. Por ejemplo:

 class ClientContext: def __init__(self, session): self.session = session async def handle_client(self, reader, writer): # ... here you get reader and writer, but also have # session etc as self.session ... async def main(): ctx = ClientContext(aiohttp.ClientSession()) await asyncio.start_server(ctx.handle_client), '', 55555)