هل هناك طريقة لمنع اكتشاف استثناء SystemExit المرفوع من sys.exit()؟
-
05-07-2019 - |
سؤال
تقول المستندات أن استدعاء sys.exit() يثير استثناء SystemExit والذي يمكن اكتشافه في المستويات الخارجية.لدي موقف أرغب فيه في الخروج بشكل نهائي وغير قابل للشك من داخل حالة اختبار، ولكن وحدة Unittest تلتقط SystemExit وتمنع الخروج.يعد هذا أمرًا رائعًا عادةً، ولكن الموقف المحدد الذي أحاول التعامل معه هو الموقف الذي اكتشف فيه إطار الاختبار الخاص بنا أنه تم تكوينه للإشارة إلى قاعدة بيانات غير اختبارية.في هذه الحالة أريد الخروج ومنع إجراء أي اختبارات أخرى.بالطبع بما أن Unittest يحاصر SystemExit ويستمر بسعادة في طريقه، فهو يحبطني.
الخيار الوحيد الذي فكرت فيه حتى الآن هو استخدام ctypes أو شيء مشابه لاستدعاء خروج (3) مباشرة ولكن هذا يبدو وكأنه اختراق قبيح جدًا لشيء يجب أن يكون بسيطًا حقًا.
المحلول
ويمكنك الاتصال os._exit()
للخروج مباشرة، دون طرح استثناء :
import os
os._exit(1)
وهذا يتجاوز كل منطق اغلاق الثعبان، مثل وحدة atexit
، وسوف يتم تشغيل من خلال منطق معالجة الاستثناء الذي كنت تحاول تجنب في هذه الحالة. والحجة هي رمز إنهاء التي سيتم إرجاعها من قبل هذه العملية.
نصائح أخرى
وكما قال يروب os._exit(1)
هو جوابك.ولكن، مع الأخذ في الاعتبار أنه يتجاوز الجميع إجراءات التنظيف، بما في ذلك finally:
الكتل وإغلاق الملفات وما إلى ذلك، ويجب تجنبها بأي ثمن، هل يمكنني تقديم طريقة "أكثر أمانًا" لاستخدامها؟
إذا كنت المشكلة SystemExit
الوقوع في المستويات الخارجية (أي، Unittest)، إذن كن المستوى الخارجي بنفسك! قم بلف الكود الرئيسي الخاص بك في كتلة محاولة/باستثناء، ثم التقط SystemExit، ثم اتصل بـ os._exit هناك، و فقط هناك! بهذه الطريقة يمكنك الاتصال sys.exit
عادةً في أي مكان في الكود، دعه يخرج إلى المستوى الأعلى، ويغلق جميع الملفات بأمان ويشغل جميع عمليات التنظيف، و ثم استدعاء os._exit.
يمكنك أيضًا اختيار مخارج "الطوارئ".الكود أدناه هو مثال على هذا النهج:
import sys, os
EMERGENCY = 255 # can be any number actually
try:
# wrap your whole code here ...
# ... some code
if x: sys.exit()
# ... some more code
if y: sys.exit(EMERGENCY) # use only for emergency exits
# ...
except SystemExit as e:
if e.code != EMERGENCY:
raise # normal exit, let unittest catch it
else:
os._exit(EMERGENCY) # try to stop *that*, sucker!