sys.monitoring --- پایش رویدادهای اجرا

اضافه شده در نسخه‌ی 3.12.


توجه

sys.monitoring یک فضای نام درون ماژول sys است، نه یک ماژول مستقل، و import sys.monitoring با یک ModuleNotFoundError شکست خواهد خورد. در عوض، به‌سادگی import sys را انجام دهید و سپس از sys.monitoring استفاده کنید.

این فضای نام دسترسی به توابع و ثابت‌های لازم برای فعال‌سازی و کنترل پایش رویدادها را فراهم می‌کند.

هنگامی که برنامه‌ها اجرا می‌شوند، رویدادهایی رخ می‌دهند که ممکن است برای ابزارهایی که اجرا را پایش می‌کنند جالب توجه باشند. فضای نام sys.monitoring امکاناتی را برای دریافت کال‌بک‌ها هنگام رخ دادن رویدادهای مورد نظر فراهم می‌کند.

API پایش از سه کامپوننت تشکیل می‌شود:

شناسه‌های ابزار

شناسه ابزار یک عدد صحیح و نام مرتبط است. شناسه‌های ابزار برای جلوگیری از تداخل ابزارها با یکدیگر و امکان فعالیت همزمان چندین ابزار به کار می‌روند. در حال حاضر ابزارها کاملاً مستقل هستند و نمی‌توان از آن‌ها برای پایش یکدیگر استفاده کرد. این محدودیت ممکن است در آینده برداشته شود.

پیش از ثبت یا فعال‌سازی رویدادها، یک ابزار باید شناسه‌ای انتخاب کند. شناسه‌ها اعداد صحیحی در بازه‌ی ۰ تا ۵ (شامل ۰ و ۵) هستند.

ثبت و استفاده از ابزارها

sys.monitoring.use_tool_id(tool_id: int, name: str, /) None

باید پیش از آنکه بتوان از tool_id استفاده کرد، فراخوانی شود. tool_id باید در بازه‌ی ۰ تا ۵ باشد (شامل ۰ و ۵). اگر tool_id در حال استفاده باشد، یک ValueError پرتاب می‌شود.

sys.monitoring.clear_tool_id(tool_id: int, /) None

ثبت تمام رویدادها و توابع کال‌بک مرتبط با tool_id را لغو می‌کند.

اضافه شده در نسخه‌ی 3.14.

sys.monitoring.free_tool_id(tool_id: int, /) None

باید هنگامی فراخوانی شود که یک ابزار دیگر به tool_id نیازی ندارد. پیش از آزادسازی tool_id، clear_tool_id() را فراخوانی می‌کند.

تغییر یافته در نسخه‌ی 3.14: Now calls clear_tool_id() before releasing tool_id. Previously, it would not disable global or local events associated with tool_id, nor unregister any callback functions.

sys.monitoring.get_tool(tool_id: int, /) str | None

اگر tool_id در حال استفاده باشد، نام ابزار را برمی‌گرداند؛ در غیر این صورت None را برمی‌گرداند. tool_id باید در بازه‌ی ۰ تا ۵ (شامل هر دو) باشد.

ماشین مجازی (VM) همه‌ی شناسه‌ها را از نظر رویدادها یکسان در نظر می‌گیرد، اما شناسه‌های زیر از پیش تعریف‌شده‌اند تا همکاری ابزارها آسان‌تر شود:

sys.monitoring.DEBUGGER_ID = 0
sys.monitoring.COVERAGE_ID = 1
sys.monitoring.PROFILER_ID = 2
sys.monitoring.OPTIMIZER_ID = 5

رویدادها

رویدادهای زیر پشتیبانی می‌شوند:

sys.monitoring.events.BRANCH_LEFT

یک شاخه‌ی شرطی به چپ می‌رود.

تعیین نحوه‌ی نمایش شاخه‌های «چپ» و «راست» بر عهده ابزار است. تضمینی وجود ندارد که کدام شاخه «چپ» و کدام «راست» باشد، به‌جز این که در طول عمر برنامه ثابت خواهد بود.

sys.monitoring.events.BRANCH_RIGHT

یک شاخه شرطی به سمت راست می‌رود.

sys.monitoring.events.CALL

یک فراخوانی در کد پایتون (رویداد پیش از فراخوانی رخ می‌دهد).

sys.monitoring.events.C_RAISE

استثنایی که از هر فراخوانی‌پذیر، به جز توابع پایتون، پرتاب می‌شود (رویداد پس از خروج رخ می‌دهد).

sys.monitoring.events.C_RETURN

بازگشت از هر فراخوانی‌پذیر، به‌جز توابع پایتون (رویداد پس از بازگشت رخ می‌دهد).

sys.monitoring.events.EXCEPTION_HANDLED

استثنایی مدیریت می‌شود.

sys.monitoring.events.INSTRUCTION

یک دستور ماشین مجازی در شرف اجرا شدن است.

sys.monitoring.events.JUMP

یک پرش غیرشرطی در گراف جریان کنترل انجام می‌شود.

sys.monitoring.events.LINE

دستوری که شماره‌ی خط متفاوتی از دستور پیشین دارد، در آستانه‌ی اجرا شدن است.

sys.monitoring.events.PY_RESUME

ازسرگیری یک تابع پایتون (برای توابع تولیدگر و هم‌روال)، به‌استثنای فراخوانی‌های throw().

sys.monitoring.events.PY_RETURN

بازگشت از یک تابع پایتون (درست پیش از بازگشت رخ می‌دهد؛ فریم تابع فراخوانی‌شده روی پشته خواهد بود).

sys.monitoring.events.PY_START

آغاز یک تابع پایتون (بلافاصله پس از فراخوانی رخ می‌دهد، فریم تابع فراخوانی‌شده روی پشته خواهد بود)

sys.monitoring.events.PY_THROW

یک تابع پایتون با فراخوانی throw() از سر گرفته می‌شود.

sys.monitoring.events.PY_UNWIND

خروج از یک تابع پایتون در حین باز شدن استثنا (exception unwinding). این شامل استثناهایی می‌شود که مستقیماً درون تابع پرتاب شده‌اند و اجازه داده می‌شود به انتشار ادامه دهند.

sys.monitoring.events.PY_YIELD

Yield از یک تابع پایتون (درست پیش از yield رخ می‌دهد، فریم فراخوانی‌شونده روی پشته خواهد بود).

sys.monitoring.events.RAISE

استثنایی پرتاب می‌شود، به‌جز آن‌هایی که رویداد STOP_ITERATION را ایجاد می‌کنند.

sys.monitoring.events.RERAISE

یک استثنا دوباره پرتاب می‌شود، برای مثال در پایان یک بلوک finally.

sys.monitoring.events.STOP_ITERATION

یک StopIteration مصنوعی پرتاب می‌شود؛ the STOP_ITERATION event را ببینید.

ممکن است رویدادهای بیشتری در آینده افزوده شوند.

این رویدادها ویژگی‌های فضای نام sys.monitoring.events هستند. هر رویداد به‌صورت یک ثابت عدد صحیح با مقدار توانی از ۲ نمایش داده می‌شود. برای تعریف مجموعه‌ای از رویدادها، کافی است رویدادهای جداگانه را با OR بیتی با هم ترکیب کنید. برای مثال، برای مشخص کردن هر دو رویداد PY_RETURN و PY_START، از عبارت PY_RETURN | PY_START استفاده کنید.

sys.monitoring.events.NO_EVENTS

نام مستعاری برای 0 تا کاربران بتوانند مقایسه‌های صریحی مانند این انجام دهند:

if get_events(DEBUGGER_ID) == NO_EVENTS:
    ...

تنظیم این رویداد، همه رویدادها را غیرفعال می‌کند.

رویدادهای محلی

رویدادهای محلی با اجرای عادی برنامه مرتبط هستند و در مکان‌های به‌وضوح تعریف‌شده رخ می‌دهند. می‌توان تمام رویدادهای محلی را غیرفعال کرد. رویدادهای محلی عبارتند از:

رویداد منسوخ

  • BRANCH

رویداد BRANCH در 3.14 منسوخ شده است. استفاده از رویدادهای BRANCH_LEFT و BRANCH_RIGHT عملکرد بسیار بهتری خواهد داشت، زیرا می‌توان آن‌ها را به‌طور مستقل غیرفعال کرد.

رویدادهای جانبی

رویدادهای کمکی را می‌توان مانند سایر رویدادها پایش کرد، اما توسط رویداد دیگری کنترل می‌شوند:

رویدادهای C_RETURN و C_RAISE توسط رویداد CALL کنترل می‌شوند. رویدادهای C_RETURN و C_RAISE تنها در صورتی مشاهده می‌شوند که رویداد CALL متناظر پایش شود.

رویدادهای دیگر

سایر رویدادها لزوماً به مکان مشخصی در برنامه وابسته نیستند و نمی‌توان آن‌ها را به‌صورت جداگانه از طریق DISABLE غیرفعال کرد.

رویدادهای دیگری که می‌توان آن‌ها را پایش کرد عبارتند از:

رویداد STOP_ITERATION

PEP 380 مشخص می‌کند که هنگام برگرداندن یک مقدار از یک تولیدگر یا هم‌روال، استثنای StopIteration پرتاب می‌شود. با این حال، این روش بسیار ناکارآمدی برای برگرداندن یک مقدار است، بنابراین برخی از پیاده‌سازی‌های پایتون، به‌ویژه CPython 3.12+، استثنایی پرتاب نمی‌کنند مگر اینکه برای کد دیگر قابل مشاهده باشد.

برای اینکه ابزارها بتوانند استثناهای واقعی را بدون کُند کردن تولیدگرها و هم‌روال‌ها پایش کنند، رویداد STOP_ITERATION فراهم شده است. STOP_ITERATION را می‌توان به‌صورت محلی غیرفعال کرد، برخلاف RAISE.

توجه داشته باشید که رویداد STOP_ITERATION و رویداد RAISE برای استثنای StopIteration معادل هستند و هنگام تولید رویدادها، به‌عنوان قابل تعویض در نظر گرفته می‌شوند. پیاده‌سازی‌ها به دلایل کارایی، STOP_ITERATION را ترجیح می‌دهند، اما ممکن است یک رویداد RAISE همراه با یک StopIteration تولید کنند.

فعال و غیرفعال کردن رویدادها

برای پایش یک رویداد، باید آن را روشن کرد و یک کال‌بک متناظر باید ثبت شود. رویدادها را می‌توان با تنظیم آن‌ها به‌صورت سراسری و/یا برای یک شیء کد (code object) خاص، روشن یا خاموش کرد. یک رویداد تنها یک‌بار فعال می‌شود، حتی اگر هم به‌صورت سراسری و هم به‌صورت محلی روشن شده باشد.

تنظیم رویدادها به‌صورت سراسری

رویدادها را می‌توان با تغییر مجموعه رویدادهای در حال پایش، به‌صورت سراسری کنترل کرد.

sys.monitoring.get_events(tool_id: int, /) int

یک int بازمی‌گرداند که همه رویدادهای فعال را نشان می‌دهد.

sys.monitoring.set_events(tool_id: int, event_set: int, /) None

تمام رویدادهایی را که در event_set تنظیم شده‌اند، فعال می‌کند. اگر tool_id در حال استفاده نباشد، یک ValueError پرتاب می‌کند.

هیچ رویدادی به‌طور پیش‌فرض فعال نیست.

رویدادها به‌ازای هر شیء کد

رویدادها را همچنین می‌توان بر اساس هر شیء کد کنترل کرد. توابع تعریف‌شده در زیر که یک types.CodeType را می‌پذیرند، باید آماده باشند تا یک شیء مشابه را از توابعی که در پایتون تعریف نشده‌اند بپذیرند (به API پایش C مراجعه کنید).

sys.monitoring.get_local_events(tool_id: int, code: CodeType, /) int

تمام رویدادهای محلی برای code را برمی‌گرداند

sys.monitoring.set_local_events(tool_id: int, code: CodeType, event_set: int, /) None

تمام رویدادهای محلی برای code را که در event_set تنظیم شده‌اند، فعال می‌کند. اگر tool_id در حال استفاده نباشد، یک ValueError پرتاب می‌کند.

غیرفعال‌سازی رویدادها

sys.monitoring.DISABLE

مقدار خاصی که می‌توان آن را از یک تابع کال‌بک بازگرداند تا رویدادها را برای موقعیت فعلی کد غیرفعال کند.

رویدادهای محلی را می‌توان برای یک موقعیت کد مشخص با برگرداندن sys.monitoring.DISABLE از یک تابع کال‌بک غیرفعال کرد. این کار، رویدادهای تنظیم‌شده یا سایر موقعیت‌های کد برای همان رویداد را تغییر نمی‌دهد.

غیرفعال کردن رویدادها برای محل‌های مشخص، برای پایش با کارایی بالا بسیار مهم است. برای مثال، اگر اشکال‌زدا همه پایش را به جز چند نقطه شکست غیرفعال کند، می‌توان یک برنامه را بدون سربار تحت یک اشکال‌زدا اجرا کرد.

اگر DISABLE توسط یک کال‌بک برای یک رویداد سراسری برگردانده شود، ValueError توسط مفسر در مکانی نامشخص پرتاب خواهد شد (یعنی هیچ ردگیری پشته‌ای ارائه نخواهد شد).

sys.monitoring.restart_events() None

تمام رویدادهایی را که توسط sys.monitoring.DISABLE غیرفعال‌شده بودند، برای همه ابزارها فعال کنید.

ثبت توابع کال‌بک

sys.monitoring.register_callback(tool_id: int, event: int, func: Callable | None, /) Callable | None

شیء فراخوانی‌پذیر func را برای event با tool_id داده‌شده ثبت می‌کند

اگر کال‌بک دیگری برای tool_id و event داده‌شده ثبت شده باشد، آن کال‌بک از ثبت خارج شده و بازگردانده می‌شود. در غیر این صورت register_callback() مقدار None را برمی‌گرداند.

یک رویداد حسابرسی sys.monitoring.register_callback را با آرگومان func پرتاب می‌کند.

می‌توان توابع را با فراخوانی sys.monitoring.register_callback(tool_id, event, None) از ثبت خارج کرد.

توابع کال‌بک را می‌توان در هر زمان ثبت و لغو ثبت کرد.

کال‌بک‌ها تنها یک بار فراخوانی می‌شوند، صرف‌نظر از اینکه رویداد هم به‌صورت سراسری و هم به‌صورت محلی فعال شده باشد. بنابراین، اگر ممکن است رویدادی توسط کد شما برای هر دو رویداد سراسری و محلی فعال شود، کال‌بک باید به‌گونه‌ای نوشته شود که هر یک از محرک‌ها را مدیریت کند.

آرگومان‌های تابع کال‌بک

sys.monitoring.MISSING

مقدار ویژه‌ای که به یک تابع کال‌بک ارسال می‌شود تا نشان دهد که آرگومانی برای فراخوانی وجود ندارد.

هنگامی که یک رویداد فعال رخ می‌دهد، تابع کال‌بک ثبت‌شده فراخوانی می‌شود. توابع کال‌بکی که شیئی غیر از DISABLE برمی‌گردانند، بی‌اثر خواهند بود. رویدادهای مختلف، آرگومان‌های مختلفی را در اختیار تابع کال‌بک قرار می‌دهند، به شرح زیر:

  • PY_START و PY_RESUME:

    func(code: CodeType, instruction_offset: int) -> object
    
  • PY_RETURN و PY_YIELD:

    func(code: CodeType, instruction_offset: int, retval: object) -> object
    
  • CALL، C_RAISE و C_RETURN (arg0 می‌تواند به‌طور خاص MISSING باشد):

    func(code: CodeType, instruction_offset: int, callable: object, arg0: object) -> object
    

    code نمایانگر شیء کدی است که فراخوانی در آن انجام می‌شود، در حالی که callable شیئی است که قرار است فراخوانی شود (و در نتیجه رویداد را فعال کرده است). اگر آرگومانی وجود نداشته باشد، arg0 برابر با sys.monitoring.MISSING تنظیم می‌شود.

    برای متدهای نمونه، callable شیء تابعی خواهد بود که در کلاس یافت می‌شود، با arg0 تنظیم‌شده به نمونه (یعنی آرگومان self متد).

  • RAISE، RERAISE، EXCEPTION_HANDLED، PY_UNWIND، PY_THROW و STOP_ITERATION:

    func(code: CodeType, instruction_offset: int, exception: BaseException) -> object
    
  • LINE:

    func(code: CodeType, line_number: int) -> object
    
  • BRANCH_LEFT، BRANCH_RIGHT و JUMP:

    func(code: CodeType, instruction_offset: int, destination_offset: int) -> object
    

    توجه داشته باشید که destination_offset محل اجرای بعدی کد است.

  • INSTRUCTION:

    func(code: CodeType, instruction_offset: int) -> object