"sys.monitoring" --- Monitoramento de eventos de execução
*********************************************************

Adicionado na versão 3.12.

======================================================================

Nota:

  "sys.monitoring" é um espaço de nomes dentro do módulo "sys", não um
  módulo independente, então não há necessidade de importá-lo com
  "import sys.monitoring", bastando usar "import sys" e então usar
  "sys.monitoring".

Esse espaço de nomes fornece acesso às funções e constantes
necessárias para ativar e controlar o monitoramento de eventos.

À medida que os programas são executados, ocorrem eventos que podem
ser de interesse para as ferramentas que monitoram a execução. O
espaço de nomes "sys.monitoring" fornece meios para receber retornos
de chamada quando ocorrem eventos de interesse.

A API de monitoramento consiste em três componentes:

* Identificadores de ferramenta

* Eventos

* Funções de retorno de chamadas


Identificadores de ferramenta
=============================

Um identificador de ferramenta é um número inteiro e o nome associado.
Os identificadores de ferramenta são usados para evitar que as
ferramentas interfiram umas nas outras e para permitir que várias
ferramentas operem ao mesmo tempo. Atualmente, as ferramentas são
totalmente independentes e não podem ser usadas para monitorar umas às
outras. Essa restrição poderá ser suspensa no futuro.

Antes de registrar ou ativar eventos, uma ferramenta deve escolher um
identificador. Os identificadores são números inteiros no intervalo de
0 a 5, inclusive.


Registro e uso de ferramentas
-----------------------------

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

   Deve ser chamado antes que *tool_id* possa ser usado. *tool_id*
   deve estar no intervalo de 0 a 5, inclusive. Levanta um
   "ValueError" se *tool_id* estiver em uso.

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

   Deve ser chamado quando uma ferramenta não precisar mais do
   endereço *tool_id*.

Nota:

  "free_tool_id()" não desabilitará eventos globais ou locais
  associados a *tool_id*, nem cancelará o registro de qualquer função
  de retorno. Essa função deve ser usada apenas para notificar a VM de
  que o *tool_id* específico não está mais em uso.

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

   Retorna o nome da ferramenta se *tool_id* estiver em uso; caso
   contrário, retorna "None". *tool_id* deve estar no intervalo de 0 a
   5, inclusive.

Todas as IDs são tratadas da mesma forma pela VM com relação aos
eventos, mas as seguintes IDs são predefinidas para facilitar a
cooperação entre as ferramentas:

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

Não há obrigação de definir uma ID, nem há nada que impeça uma
ferramenta de usar uma ID, mesmo que ela já esteja em uso. No entanto,
as ferramentas são incentivadas a usar uma ID exclusiva e a respeitar
as outras ferramentas.


Eventos
=======

Os seguintes eventos são suportados:

sys.monitoring.events.BRANCH

   Uma ramificação condicional é feita (ou não).

sys.monitoring.events.CALL

   Uma chamada no código Python (o evento ocorre antes da chamada).

sys.monitoring.events.C_RAISE

   Uma exceção levantada por qualquer chamável, exceto funções Python
   (o evento ocorre após a saída).

sys.monitoring.events.C_RETURN

   Retorno de qualquer chamável, exceto por funções Python (o evento
   ocorre após o retorno).

sys.monitoring.events.EXCEPTION_HANDLED

   Uma exceção é tratada.

sys.monitoring.events.INSTRUCTION

   Uma instrução VM está prestes a ser executada.

sys.monitoring.events.JUMP

   É feito um salto incondicional no gráfico do fluxo de controle.

sys.monitoring.events.LINE

   Está prestes a ser executada uma instrução que tem um número de
   linha diferente da instrução anterior.

sys.monitoring.events.PY_RESUME

   Retomada de uma função Python (para funções geradoras e de
   corrotina), exceto para chamadas "throw()".

sys.monitoring.events.PY_RETURN

   Retorno de uma função Python (ocorre imediatamente antes do
   retorno, o quadro do receptor estará na pilha).

sys.monitoring.events.PY_START

   Início de uma função Python (ocorre imediatamente após a chamada, o
   quadro do receptor da chamada estará na pilha)

sys.monitoring.events.PY_THROW

   Uma função Python é retomada por uma chamada "throw()".

sys.monitoring.events.PY_UNWIND

   Saída de uma função Python durante o desenrolar da exceção.

sys.monitoring.events.PY_YIELD

   Produz de uma função Python (ocorre imediatamente antes do yield, o
   quadro do receptor estará na pilha).

sys.monitoring.events.RAISE

   Uma exceção é levantada, exceto aquelas que causam um evento
   "STOP_ITERATION".

sys.monitoring.events.RERAISE

   Uma exceção é levantada novamente, por exemplo, no final de um
   bloco "finally".

sys.monitoring.events.STOP_ITERATION

   Uma exceção artificial "StopIteration" é levantada; consulte o
   evento STOP_ITERATION.

Mais eventos poderão ser adicionados no futuro.

Esses eventos são atributos do espaço de nomes
"sys.monitoring.events". Cada evento é representado como uma constante
de potência de 2 inteiros. Para definir um conjunto de eventos, basta
usar o bit a bit ou os eventos individuais juntos. Por exemplo, para
especificar os eventos "PY_RETURN" e "PY_START", use a expressão
"PY_RETURN | PY_START".

sys.monitoring.events.NO_EVENTS

   Um apelido para "0" para que os usuários possam fazer comparações
   explícitas como:

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

Os eventos são divididos em três grupos:


Eventos locais
--------------

Os eventos locais estão associados à execução normal do programa e
ocorrem em locais claramente definidos. Todos os eventos locais podem
ser desativados. Os eventos locais são:

* "PY_START"

* "PY_RESUME"

* "PY_RETURN"

* "PY_YIELD"

* "CALL"

* "LINE"

* "INSTRUCTION"

* "JUMP"

* "BRANCH"

* "STOP_ITERATION"


Eventos auxiliares
------------------

Os eventos auxiliares podem ser monitorados como outros eventos, mas
são controlados por outro evento:

* "C_RAISE"

* "C_RETURN"

Os eventos "C_RETURN" e "C_RAISE" são controlados pelo evento "CALL".
Os eventos "C_RETURN" e "C_RAISE" só serão vistos se o evento "CALL"
correspondente estiver sendo monitorado.


Outros eventos
--------------

Outros eventos não estão necessariamente vinculados a um local
específico no programa e não podem ser desativados individualmente.

Os outros eventos que podem ser monitorados são:

* "PY_THROW"

* "PY_UNWIND"

* "RAISE"

* "EXCEPTION_HANDLED"


O evento STOP_ITERATION
-----------------------

**PEP 380** especifica que uma exceção "StopIteration" é levantada ao
retornar um valor de um gerador ou corrotina. No entanto, essa é uma
maneira muito ineficiente de retornar um valor, portanto, algumas
implementações do Python, especialmente o CPython 3.12+, não levantam
uma exceção, a menos que ela seja visível para outro código.

Para permitir que as ferramentas monitorem exceções reais sem reduzir
a velocidade dos geradores e das corrotinas, o evento "STOP_ITERATION"
é fornecido. O "STOP_ITERATION" pode ser desativado localmente, ao
contrário do "RAISE".


Ativação e desativação de eventos
=================================

Para monitorar um evento, ele deve ser ativado e uma função de retorno
correspondente deve ser registrada. Os eventos podem ser ativados ou
desativados definindo-os globalmente ou para um objeto código
específico.


Definir eventos globalmente
---------------------------

Os eventos podem ser controlados globalmente, modificando o conjunto
de eventos que estão sendo monitorados.

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

   Retorna o endereço "int" que representa todos os eventos ativos.

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

   Ativa todos os eventos definidos em *event_set*. Levanta um
   "ValueError" se *tool_id* não estiver em uso.

Nenhum evento está ativo por padrão.


Eventos por objeto código
-------------------------

Os eventos também podem ser controlados com base em cada objeto
código.

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

   Retorna todos os eventos locais para *code*

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

   Ativa todos os eventos locais para *code* que estão definidos em
   *event_set*. Levanta a "ValueError" se *tool_id* não estiver em
   uso.

Os eventos locais são adicionados aos eventos globais, mas não os
mascaram. Em outras palavras, todos os eventos globais serão acionados
para um objeto código, independentemente dos eventos locais.


Desativação de eventos
----------------------

sys.monitoring.DISABLE

   Um valor especial que pode ser retornado de um função de retorno
   função para desativar eventos para o local do código atual.

Os eventos locais podem ser desativados para um local de código
específico, retornando "sys.monitoring.DISABLE" de uma função de
retorno de chamada. Isso não altera quais eventos são definidos ou
quaisquer outros locais de código para o mesmo evento.

A desativação de eventos para locais específicos é muito importante
para o monitoramento de alto desempenho. Por exemplo, um programa pode
ser executado em um depurador sem sobrecarga se o depurador desativar
todo o monitoramento, exceto alguns pontos de interrupção.

sys.monitoring.restart_events() -> None

   Habilita todos os eventos que foram desabilitados por
   "sys.monitoring.DISABLE" para todas as ferramentas.


Registro de funções de retorno de chamada
=========================================

Para registrar um chamável para eventos, chame

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

   Registra o chamável *func* para o *event* com o *tool_id* fornecido

   Se outra função de retorno tiver sido registrada para o *tool_id* e
   o *event* fornecidos, ela será cancelada e retornada. Caso
   contrário, "register_callback()" retorna "None".

As funções podem ser canceladas chamando
"sys.monitoring.register_callback(tool_id, event, None)".

As funções de retorno de chamada podem ser registradas e canceladas a
qualquer momento.

O registro ou o cancelamento do registro de uma função de retorno de
chamada gerará um evento "sys.audit()".


Argumentos da função de retorno de chamada
------------------------------------------

sys.monitoring.MISSING

   Um valor especial que é passado para uma função de retorno para
   indicar que não há argumento para a chamada.

Quando ocorre um evento ativo, a função de retorno de chamada
registrada é chamada. Eventos diferentes fornecerão à função de
retorno de chamada argumentos diferentes, como segue:

* "PY_START" e "PY_RESUME":

     func(code: CodeType, instruction_offset: int) -> DISABLE | Any

* "PY_RETURN" e "PY_YIELD":

     func(code: CodeType, instruction_offset: int, retval: object) -> DISABLE | Any

* "CALL", "C_RAISE" e "C_RETURN":

     func(code: CodeType, instruction_offset: int, callable: object, arg0: object | MISSING) -> DISABLE | Any

  Se não houver argumentos, *arg0* será definido como
  "sys.monitoring.MISSING".

* "RAISE", "RERAISE", "EXCEPTION_HANDLED", "PY_UNWIND", "PY_THROW" e
  "STOP_ITERATION":

     func(code: CodeType, instruction_offset: int, exception: BaseException) -> DISABLE | Any

* "LINE":

     func(code: CodeType, line_number: int) -> DISABLE | Any

* "BRANCH" e "JUMP":

     func(code: CodeType, instruction_offset: int, destination_offset: int) -> DISABLE | Any

  Observe que *destination_offset* é onde o código será executado em
  seguida. Para uma ramificação não executada, esse será o
  deslocamento da instrução que segue a ramificação.

* "INSTRUCTION":

     func(code: CodeType, instruction_offset: int) -> DISABLE | Any
