From 0dcae29b0048f8d01829f5fa36ca1d57467fc9ff Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 13 May 2025 12:24:26 -0700 Subject: [PATCH 1/8] Clarify some details regarding `sys.monitoring` --- Doc/library/sys.monitoring.rst | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/Doc/library/sys.monitoring.rst b/Doc/library/sys.monitoring.rst index 0674074b8c0df6..7d1b23ca41a861 100644 --- a/Doc/library/sys.monitoring.rst +++ b/Doc/library/sys.monitoring.rst @@ -171,7 +171,9 @@ events, use the expression ``PY_RETURN | PY_START``. if get_events(DEBUGGER_ID) == NO_EVENTS: ... -Events are divided into three groups: + Setting this event deactivates all events. + +Events can be divided into groups: .. _monitoring-event-local: @@ -292,9 +294,10 @@ in Python (see :ref:`c-api-monitoring`). Activates all the local events for *code* which are set in *event_set*. Raises a :exc:`ValueError` if *tool_id* is not in use. -Local events add to global events, but do not mask them. -In other words, all global events will trigger for a code object, -regardless of the local events. +Local events add to global events. In other words, all global events +will trigger for a code object, regardless of the local events. Events +will also only trigger once regardless of whether the same event is +registered both globally and locally for a code object. Disabling events @@ -325,8 +328,6 @@ except for a few breakpoints. Registering callback functions ------------------------------ -To register a callable for events call - .. function:: register_callback(tool_id: int, event: int, func: Callable | None, /) -> Callable | None Registers the callable *func* for the *event* with the given *tool_id* @@ -367,8 +368,15 @@ Different events will provide the callback function with different arguments, as func(code: CodeType, instruction_offset: int, callable: object, arg0: object | MISSING) -> DISABLE | Any + *code* represents the code object where the call is being made, while + *callable* is the object that is about to be called (and thus + triggered the event). If there are no arguments, *arg0* is set to :data:`sys.monitoring.MISSING`. + For instance methods, *callable* will be the function object as found on the + class with *arg0* set to the instance (i.e. the ``self`` argument to the + method). + * :monitoring-event:`RAISE`, :monitoring-event:`RERAISE`, :monitoring-event:`EXCEPTION_HANDLED`, :monitoring-event:`PY_UNWIND`, :monitoring-event:`PY_THROW` and :monitoring-event:`STOP_ITERATION`:: From 37fde1bd95eb71f57e169f1e231eaeac412ed436 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 13 May 2025 12:26:33 -0700 Subject: [PATCH 2/8] Drop a lead-in sentence --- Doc/library/sys.monitoring.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/Doc/library/sys.monitoring.rst b/Doc/library/sys.monitoring.rst index 7d1b23ca41a861..bbe3864f7e61fc 100644 --- a/Doc/library/sys.monitoring.rst +++ b/Doc/library/sys.monitoring.rst @@ -173,8 +173,6 @@ events, use the expression ``PY_RETURN | PY_START``. Setting this event deactivates all events. -Events can be divided into groups: - .. _monitoring-event-local: Local events From f346fc7623f45c1e37c38853667f36ce9e3355f8 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 27 May 2025 11:46:52 -0700 Subject: [PATCH 3/8] Fix type signatures for callback examples --- Doc/library/sys.monitoring.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Doc/library/sys.monitoring.rst b/Doc/library/sys.monitoring.rst index bbe3864f7e61fc..9b6a5bedd98927 100644 --- a/Doc/library/sys.monitoring.rst +++ b/Doc/library/sys.monitoring.rst @@ -356,15 +356,15 @@ Different events will provide the callback function with different arguments, as * :monitoring-event:`PY_START` and :monitoring-event:`PY_RESUME`:: - func(code: CodeType, instruction_offset: int) -> DISABLE | Any + func(code: CodeType, instruction_offset: int) -> object # DISABLE | Any * :monitoring-event:`PY_RETURN` and :monitoring-event:`PY_YIELD`:: - func(code: CodeType, instruction_offset: int, retval: object) -> DISABLE | Any + func(code: CodeType, instruction_offset: int, retval: object) -> object # DISABLE | Any -* :monitoring-event:`CALL`, :monitoring-event:`C_RAISE` and :monitoring-event:`C_RETURN`:: +* :monitoring-event:`CALL`, :monitoring-event:`C_RAISE` and :monitoring-event:`C_RETURN` (*arg0* can be :data:`MISSING`):: - func(code: CodeType, instruction_offset: int, callable: object, arg0: object | MISSING) -> DISABLE | Any + func(code: CodeType, instruction_offset: int, callable: object, arg0: object) -> object # DISABLE | Any *code* represents the code object where the call is being made, while *callable* is the object that is about to be called (and thus @@ -378,7 +378,7 @@ Different events will provide the callback function with different arguments, as * :monitoring-event:`RAISE`, :monitoring-event:`RERAISE`, :monitoring-event:`EXCEPTION_HANDLED`, :monitoring-event:`PY_UNWIND`, :monitoring-event:`PY_THROW` and :monitoring-event:`STOP_ITERATION`:: - func(code: CodeType, instruction_offset: int, exception: BaseException) -> DISABLE | Any + func(code: CodeType, instruction_offset: int, exception: BaseException) -> object # DISABLE | Any * :monitoring-event:`LINE`:: @@ -386,10 +386,10 @@ Different events will provide the callback function with different arguments, as * :monitoring-event:`BRANCH_LEFT`, :monitoring-event:`BRANCH_RIGHT` and :monitoring-event:`JUMP`:: - func(code: CodeType, instruction_offset: int, destination_offset: int) -> DISABLE | Any + func(code: CodeType, instruction_offset: int, destination_offset: int) -> object # DISABLE | Any Note that the *destination_offset* is where the code will next execute. * :monitoring-event:`INSTRUCTION`:: - func(code: CodeType, instruction_offset: int) -> DISABLE | Any + func(code: CodeType, instruction_offset: int) -> object # DISABLE | Any From 0d53375af0fae1388013a9415f5b075119e2bd9e Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 28 May 2025 11:43:07 -0700 Subject: [PATCH 4/8] Tweak type annotations --- Doc/library/sys.monitoring.rst | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Doc/library/sys.monitoring.rst b/Doc/library/sys.monitoring.rst index 9b6a5bedd98927..ef892be5926e41 100644 --- a/Doc/library/sys.monitoring.rst +++ b/Doc/library/sys.monitoring.rst @@ -352,19 +352,21 @@ Callback function arguments that there are no arguments to the call. When an active event occurs, the registered callback function is called. +Callback functions returning any object other than :data:`DISABLE` will have no effect. Different events will provide the callback function with different arguments, as follows: * :monitoring-event:`PY_START` and :monitoring-event:`PY_RESUME`:: - func(code: CodeType, instruction_offset: int) -> object # DISABLE | Any + func(code: CodeType, instruction_offset: int) -> object * :monitoring-event:`PY_RETURN` and :monitoring-event:`PY_YIELD`:: - func(code: CodeType, instruction_offset: int, retval: object) -> object # DISABLE | Any + func(code: CodeType, instruction_offset: int, retval: object) -> object -* :monitoring-event:`CALL`, :monitoring-event:`C_RAISE` and :monitoring-event:`C_RETURN` (*arg0* can be :data:`MISSING`):: +* :monitoring-event:`CALL`, :monitoring-event:`C_RAISE` and :monitoring-event:`C_RETURN` + (*arg0* can be :data:`MISSING` specifically):: - func(code: CodeType, instruction_offset: int, callable: object, arg0: object) -> object # DISABLE | Any + func(code: CodeType, instruction_offset: int, callable: object, arg0: object) -> object *code* represents the code object where the call is being made, while *callable* is the object that is about to be called (and thus @@ -378,18 +380,18 @@ Different events will provide the callback function with different arguments, as * :monitoring-event:`RAISE`, :monitoring-event:`RERAISE`, :monitoring-event:`EXCEPTION_HANDLED`, :monitoring-event:`PY_UNWIND`, :monitoring-event:`PY_THROW` and :monitoring-event:`STOP_ITERATION`:: - func(code: CodeType, instruction_offset: int, exception: BaseException) -> object # DISABLE | Any + func(code: CodeType, instruction_offset: int, exception: BaseException) -> object * :monitoring-event:`LINE`:: - func(code: CodeType, line_number: int) -> DISABLE | Any + func(code: CodeType, line_number: int) -> object * :monitoring-event:`BRANCH_LEFT`, :monitoring-event:`BRANCH_RIGHT` and :monitoring-event:`JUMP`:: - func(code: CodeType, instruction_offset: int, destination_offset: int) -> object # DISABLE | Any + func(code: CodeType, instruction_offset: int, destination_offset: int) -> object Note that the *destination_offset* is where the code will next execute. * :monitoring-event:`INSTRUCTION`:: - func(code: CodeType, instruction_offset: int) -> object # DISABLE | Any + func(code: CodeType, instruction_offset: int) -> object From 326b31e612abc5baa45880ad56921fc54387e7f2 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 17 Jun 2025 12:10:50 -0700 Subject: [PATCH 5/8] Try clarifying that event activation locally and globally --- Doc/library/sys.monitoring.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Doc/library/sys.monitoring.rst b/Doc/library/sys.monitoring.rst index ef892be5926e41..948d339fd3cca2 100644 --- a/Doc/library/sys.monitoring.rst +++ b/Doc/library/sys.monitoring.rst @@ -292,10 +292,9 @@ in Python (see :ref:`c-api-monitoring`). Activates all the local events for *code* which are set in *event_set*. Raises a :exc:`ValueError` if *tool_id* is not in use. -Local events add to global events. In other words, all global events -will trigger for a code object, regardless of the local events. Events -will also only trigger once regardless of whether the same event is -registered both globally and locally for a code object. +Events will only trigger once, regardless of whether the same event is +activated globally as well as locally for a code object. Local activation +also doesn't impact a global registration for the same event and vice-versa. Disabling events From 93e25eb74223b2e3bda83a49d98fe123c58dd5e3 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 17 Jun 2025 12:28:37 -0700 Subject: [PATCH 6/8] Shift some things around --- Doc/library/sys.monitoring.rst | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/Doc/library/sys.monitoring.rst b/Doc/library/sys.monitoring.rst index 948d339fd3cca2..706d6d8b137a61 100644 --- a/Doc/library/sys.monitoring.rst +++ b/Doc/library/sys.monitoring.rst @@ -243,20 +243,23 @@ raise an exception unless it would be visible to other code. To allow tools to monitor for real exceptions without slowing down generators and coroutines, the :monitoring-event:`STOP_ITERATION` event is provided. -:monitoring-event:`STOP_ITERATION` can be locally disabled, unlike :monitoring-event:`RAISE`. +:monitoring-event:`STOP_ITERATION` can be locally disabled, unlike +:monitoring-event:`RAISE`. -Note that the :monitoring-event:`STOP_ITERATION` event and the :monitoring-event:`RAISE` -event for a :exc:`StopIteration` exception are equivalent, and are treated as interchangeable -when generating events. Implementations will favor :monitoring-event:`STOP_ITERATION` for -performance reasons, but may generate a :monitoring-event:`RAISE` event with a :exc:`StopIteration`. +Note that the :monitoring-event:`STOP_ITERATION` event and the +:monitoring-event:`RAISE` event for a :exc:`StopIteration` exception are +equivalent, and are treated as interchangeable when generating events. +Implementations will favor :monitoring-event:`STOP_ITERATION` for performance +reasons, but may generate a :monitoring-event:`RAISE` event with a +:exc:`StopIteration`. Turning events on and off ------------------------- In order to monitor an event, it must be turned on and a corresponding callback -must be registered. -Events can be turned on or off by setting the events either globally or -for a particular code object. +must be registered. Events can be turned on or off by setting the events either +globally and/or for a particular code object. An event will trigger only once, +even if it is turned on both globally and locally. Setting events globally @@ -292,10 +295,6 @@ in Python (see :ref:`c-api-monitoring`). Activates all the local events for *code* which are set in *event_set*. Raises a :exc:`ValueError` if *tool_id* is not in use. -Events will only trigger once, regardless of whether the same event is -activated globally as well as locally for a code object. Local activation -also doesn't impact a global registration for the same event and vice-versa. - Disabling events '''''''''''''''' @@ -333,12 +332,16 @@ Registering callback functions it is unregistered and returned. Otherwise :func:`register_callback` returns ``None``. - Functions can be unregistered by calling ``sys.monitoring.register_callback(tool_id, event, None)``. Callback functions can be registered and unregistered at any time. +Callbacks are called only once regardless if the event is turned on both +globally and locally. As such, if an event could be turned on for both global +and local events by your code then the callback needs to be written to handle +either trigger. + Registering or unregistering a callback function will generate a :func:`sys.audit` event. From 4284e0693add11d60184f69a3985fff74a531cc9 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 17 Jun 2025 16:21:15 -0700 Subject: [PATCH 7/8] Clarify that `PY_UNWIND` includes directly raised exceptions --- Doc/library/sys.monitoring.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/library/sys.monitoring.rst b/Doc/library/sys.monitoring.rst index 706d6d8b137a61..b698f12e0d3392 100644 --- a/Doc/library/sys.monitoring.rst +++ b/Doc/library/sys.monitoring.rst @@ -137,7 +137,8 @@ The following events are supported: .. monitoring-event:: PY_UNWIND - Exit from a Python function during exception unwinding. + Exit from a Python function during exception unwinding. This includes exceptions raised directly within the + function and that are allowed to continue to propagate. .. monitoring-event:: PY_YIELD From 75f9d6f86df7e2a8c695d5e9a8359806dd246d31 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Thu, 19 Jun 2025 11:43:33 -0700 Subject: [PATCH 8/8] Tweak phrasing --- Doc/library/sys.monitoring.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/sys.monitoring.rst b/Doc/library/sys.monitoring.rst index b698f12e0d3392..f62a4011e4144b 100644 --- a/Doc/library/sys.monitoring.rst +++ b/Doc/library/sys.monitoring.rst @@ -355,7 +355,7 @@ Callback function arguments that there are no arguments to the call. When an active event occurs, the registered callback function is called. -Callback functions returning any object other than :data:`DISABLE` will have no effect. +Callback functions returning an object other than :data:`DISABLE` will have no effect. Different events will provide the callback function with different arguments, as follows: * :monitoring-event:`PY_START` and :monitoring-event:`PY_RESUME`::