<p>aiohttp no debería invocar el controlador de excepciones para situaciones no excepcionales</p>

Creado en 10 nov. 2020  ·  4Comentarios  ·  Fuente: aio-libs/aiohttp

🐞 Describe el error
Cuando se filtran ciertos objetos de aiohttp, invocan el manejador de excepciones asyncio, que en algunos entornos (por ejemplo, cuando se usa aiorun , con stop_on_unhandled_errors=True ) significa que todo el programa está detenido.

Por ejemplo, aquí está el código relevante en ClientResponse :

https://github.com/aio-libs/aiohttp/blob/a8d9ec3f1667463e80545b1cacc7833d1ff305e9/aiohttp/client_reqrep.py#L748 -L751

💡 Reproducir
Filtra un objeto aiohttp que hace esto.

💡 Comportamiento esperado
Los objetos con fugas no deberían causar una excepción, por la misma razón que open() ing un archivo y no .close() ing, no genera una excepción.

Todos los objetos que hacen esto parecen generar una advertencia sobre la fuga de recursos; no veo una razón para que invoquen también el controlador de excepciones.

📋 Tu versión de Python

$ python --version
Python 3.8.6

📋 Su versión de las distribuciones aiohttp / yarl / multidict

$ python -m pip show aiohttp
Name: aiohttp
Version: 3.6.2

consola
$ python -m pip mostrar multidict
Nombre: multidict
Versión: 4.7.6

```console
$ python -m pip show yarl
Name: yarl
Version: 1.5.1

📋 Contexto adicional
cjrh / aiorun # 56

bug wontfix

Todos 4 comentarios

Estoy en desacuerdo.
El recurso no cerrado es un error de programación bastante grave que se puede solucionar fácilmente escribiendo el código correcto.
Por ejemplo, el propio asyncio usa call_exception_handler() para informar sobre llamadas asincrónicas no esperadas.
Si no desea escribir código pedante, puede usar stop_on_unhandled_errors=False .

Entonces, ¿por qué no plantear una verdadera excepción?

Supongo que porque generar una excepción en __del__ será ignorada. Pero así debe ser, ¿no? Es muy difícil depurar "algo asigna un objeto y no lo cierra correctamente", especialmente cuando el error no está en su propio código sino en alguna biblioteca; la clave de contexto source_traceback no está documentada, y parece poco amigable confiar en el comportamiento no documentado del manejador de excepciones predeterminado de asyncio para hacer posible la depuración de fugas de memoria.

Tampoco veo dónde asyncio usa call_exception_handler() para advertir sobre corrutinas no esperadas. Cuando una corrutina no esperada se recolecta como basura, invoca _PyErr_WarnUnawaitedCoroutine :

    /* If `gen` is a coroutine, and if it was never awaited on,
       issue a RuntimeWarning. */
    if (gen->gi_code != NULL &&
        ((PyCodeObject *)gen->gi_code)->co_flags & CO_COROUTINE &&
        gen->gi_frame->f_lasti == -1)
    {
        _PyErr_WarnUnawaitedCoroutine((PyObject *)gen);
    }

que invoca warnings._warn_unawaited_coroutine() :

void
_PyErr_WarnUnawaitedCoroutine(PyObject *coro)
{
    /* First, we attempt to funnel the warning through
       warnings._warn_unawaited_coroutine.

que emite un RuntimeWarning. No veo el uso de call_exception_handler() ningún lugar allí; de hecho, no veo ningún uso de call_exception_handler() en stdlib que no incluya exception en el contexto.

Y de nuevo: si olvidar cerrar un archivo no genera una excepción, ¿por qué debería olvidarse de limpiar cualquier objeto aiohttp aleatorio?

Tiene razón, plantear una excepción del método __del__ es una práctica desaconsejada.
Por eso necesitamos otra solución de señalización.
Asyncio hace llamada call_exception_handler() de __del__ , véase Task.__del__ por ejemplo: https://github.com/python/cpython/blob/master/Lib/asyncio/tasks.py # L139 -L148

Tienes razón, source_traceback no está documentado en https://docs.python.org/3/library/asyncio-eventloop.html?highlight=call_exception_handler#asyncio.loop.call_exception_handler
¿Le importaría crear una solicitud de extracción en https://github.com/python/cpython/ para corregir la documentación? Me complace revisarlo / fusionarlo.

Y de nuevo: si olvidar cerrar un archivo no genera una excepción, ¿por qué debería olvidarse de limpiar cualquier objeto aiohttp aleatorio?

aiohttp no plantea una excepción a __del__ también, es simplemente imposible en Python, porque la llamada del finalizador objeto es indeterminista.

El archivo no cerrado genera un ResourceWarning . Esta advertencia se ignora de forma predeterminada: https://docs.python.org/3/library/warnings.html#default -warning-filter
Es por eso que este tipo de advertencias no es visible para muchos desarrolladores si no las habilitan explícitamente. Esto se hace parcialmente por razones históricas: durante mucho tiempo este tipo de advertencia no existió, muchas bibliotecas no llaman file.close() porque sus autores no son conscientes de la necesidad de una limpieza elegante de los recursos, etc., etc. .

Afortunadamente, file.close() podría llamarse desde file.__del__ forma segura, es una llamada normal.
Pero en el mundo asyncio close() es diferente muy a menudo: tiene que ser una función async que simplemente no se puede llamar desde __del__ .
Por ejemplo, transport.close() sin esperar protocol.connection_lost() genera advertencias incluso para sockets simples; para SSL, la situación es aún peor.
aiohttp tiene un pequeño lío con los finalizadores de sincronización / asíncrono, pero estoy trabajando en ello; aiohttp 4.0 debe limpiarse significativamente.

Es por eso que la limpieza es muy importante, se debe generar una advertencia y se usará call_exception_handler() para hacer más visible el mal uso.

Asyncio _does_ llamar call_exception_handler() desde __del__ , ver Task.__del__ por ejemplo

Muy bien, perdí esa llamada.

¿Le importaría crear una solicitud de extracción en python / cpython para corregir la documentación?

Honestamente, no estoy seguro de cuál es la mejor manera de documentarlo. Creé bpo-42347 ya que noté algunas otras discrepancias entre los documentos, la cadena de documentos y la implementación.

Es por eso que la limpieza es muy importante, se debe generar una advertencia y se usará call_exception_handler () para hacer que el mal uso sea más visible.

Supongo que es frustrante cuando obtienes errores porque una biblioteca que estás usando no se limpia correctamente. No me di cuenta de que era tan importante que debería detener la aplicación, e inicialmente ni siquiera me di cuenta de que la fuga era la razón por la que aiorun estaba deteniendo el ciclo.

¿Fue útil esta página
0 / 5 - 0 calificaciones