<p>يجب ألا تستدعي aiohttp معالج الاستثناء للحالات غير الاستثنائية</p>

تم إنشاؤها على ١٠ نوفمبر ٢٠٢٠  ·  4تعليقات  ·  مصدر: aio-libs/aiohttp

🐞 وصف الخطأ
عندما يتم تسريب كائنات معينة من aiohttp ، فإنها تستدعي معالج استثناء Asyncio ، والذي يعني في بعض البيئات (على سبيل المثال عند استخدام aiorun ، مع stop_on_unhandled_errors=True ) توقف البرنامج بأكمله.

على سبيل المثال ، إليك الشفرة ذات الصلة بـ ClientResponse :

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

💡 التكاثر
تسرب كائن aiohttp الذي يقوم بذلك.

💡 السلوك المتوقع
لا ينبغي أن تتسبب الكائنات المتسربة في استثناء ، لنفس السبب الذي يجعل الملف open() ing وليس .close() ing يُثير استثناءً.

يبدو أن جميع الكائنات التي تفعل ذلك تثير بالفعل تحذيرًا بشأن تسرب المورد - لا أرى سببًا لاستدعاء معالج الاستثناء أيضًا.

📋 نسختك من Python

$ python --version
Python 3.8.6

📋 نسختك من توزيعات aiohttp / yarl / multidict

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

"" تعزية
عرض نقاط بيثون $ -m multidict
الاسم: multidict
الإصدار: 4.7.6.1

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

سياق إضافي
cjrh / aiorun # 56

bug wontfix

ال 4 كومينتر

أنا أعترض.
المورد غير المغلق هو خطأ برمجة خطير بدرجة كافية يمكن إصلاحه بسهولة عن طريق كتابة الكود الصحيح.
على سبيل المثال ، يستخدم Asyncio نفسه call_exception_handler() للإبلاغ عن المكالمات غير المتزامنة غير المرغوب فيها.
إذا كنت لا تريد كتابة رمز متحذلق - يمكنك استخدام stop_on_unhandled_errors=False .

إذن ، لماذا لا نثير استثناءً حقيقيًا إذن؟

أعتقد أنه سيتم تجاهل رفع استثناء في __del__ . ولكن هذا ما ينبغي أن يكون ، أليس كذلك؟ من الصعب جدًا تصحيح "شيء ما يخصص كائنًا ولا يغلقه بشكل صحيح" ، خاصة عندما لا يكون الخطأ في التعليمات البرمجية الخاصة بك ولكن في بعض المكتبات ؛ مفتاح السياق source_traceback غير موثق ، ويبدو من غير المألوف الاعتماد على السلوك غير الموثق لمعالج الاستثناء الافتراضي الخاص بـ asyncio لتمكين تصحيح أخطاء الذاكرة.

لا أرى أيضًا أين يستخدم Asyncio call_exception_handler() للتحذير من coroutines غير المرغوب فيها. عندما يتم جمع coroutine غير المرغوب فيه من القمامة ، فإنه يستدعي _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);
    }

التي تستدعي warnings._warn_unawaited_coroutine() :

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

الذي يصدر تحذير وقت التشغيل. لا أرى استخدام call_exception_handler() أي مكان هناك - في الحقيقة لا أرى أي استخدام لـ call_exception_handler() في stdlib لا يتضمن exception في السياق.

ومرة أخرى: إذا كان نسيان إغلاق ملف لا يثير استثناءً ، فلماذا ننسى تنظيف أي كائن عشوائي من عناصر aiohttp؟

أنت محق ، فإن رفع استثناء من طريقة __del__ ممارسة غير مرغوب فيها.
لهذا السبب نحتاج إلى حل آخر للإشارات.
يقوم Asyncio باستدعاء call_exception_handler() من __del__ ، راجع Task.__del__ على سبيل المثال: https://github.com/python/cpython/blob/master/Lib/asyncio/tasks.py # L139 -L148

أنت محق ، source_traceback غير موثق في https://docs.python.org/3/library/asyncio-eventloop.html؟highlight=call_exception_handler#asyncio.loop.call_exception_handler
هل تمانع في إنشاء طلب سحب على https://github.com/python/cpython/ لإصلاح الوثائق؟ يسعدني مراجعتها / دمجها.

ومرة أخرى: إذا كان نسيان إغلاق ملف لا يثير استثناءً ، فلماذا ننسى تنظيف أي كائن عشوائي من عناصر aiohttp؟

لا يثير aiohttp استثناءً من __del__ أيضًا ، إنه مستحيل في Python لأن استدعاء الكائن النهائي غير محدد.

الملف غير المغلق يثير ResourceWarning . يتم تجاهل هذا التحذير افتراضيًا: https://docs.python.org/3/library/warnings.html#default -warning-filter
هذا هو السبب في أن هذا النوع من التحذيرات غير مرئي للعديد من المطورين إذا لم يقوموا بتمكينها بشكل صريح. يتم ذلك جزئيًا لأسباب تاريخية: لفترة طويلة لم يكن هذا النوع من التحذير موجودًا ، والعديد من المكتبات لا تتصل بـ file.close() لأن مؤلفيها ليسوا على دراية بالحاجة إلى تنظيف جيد للموارد ، وما إلى ذلك ، وما إلى ذلك. .

لحسن الحظ ، يمكن استدعاء file.close() من file.__del__ بأمان ، إنها مكالمة عادية.
ولكن في عالم Asyncio ، يختلف close() كثير من الأحيان: يجب أن تكون وظيفة غير متزامنة لا يمكن استدعاؤها من __del__ .
على سبيل المثال ، يؤدي transport.close() بدون انتظار protocol.connection_lost() إلى تحذيرات حتى بالنسبة للمآخذ العادية ؛ بالنسبة لـ SSL ، فإن الوضع أسوأ.
يحتوي aiohttp على القليل من الفوضى مع sync / async finalizers لكنني أعمل عليها ؛ يجب تنظيف aiohttp 4.0 بشكل ملحوظ.

هذا هو سبب أهمية التنظيف ، يجب رفع تحذير ، وسيتم استخدام call_exception_handler() لجعل الاستخدام السيئ أكثر وضوحًا.

Asyncio _does_ call call_exception_handler() من __del__ ، انظر Task.__del__ على سبيل المثال

عادل بما فيه الكفاية ، فاتني تلك المكالمة.

هل تمانع في إنشاء طلب سحب على python / cpython لإصلاح الوثائق؟

أنا بصراحة غير متأكد من أفضل السبل لتوثيق ذلك. لقد قمت بإنشاء bpo-42347 منذ أن لاحظت بعض التناقضات الأخرى بين المستندات ، و docstring ، والتنفيذ.

هذا هو سبب أهمية التنظيف ، يجب رفع تحذير ، وسيتم استخدام call_exception_handler () لجعل الاستخدام السيئ أكثر وضوحًا.

أعتقد أنه أمر محبط عندما تحصل على أخطاء لأن المكتبة التي تستخدمها لا تنظف بعد نفسها بشكل صحيح. لم أكن أدرك أنه كان من المهم جدًا إيقاف التطبيق ، ولم أدرك حتى في البداية أن التسريب هو السبب في قيام aiorun بإيقاف الحلقة.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات