sys.monitoring — Monitoramento de eventos de execução

Novo 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

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:

Eventos auxiliares

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

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:

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