Confusing behavior with `sys.monitoring.DISABLE`
Ninguém assumiu esta issue ainda.
- Linguagem predominante
- Python
- Estrelas
- 77.2k
- Forks
- 36k
- Métricas de merge de PRs
- Métricas de PR pendentes
Descrição
Bug report
Bug description:
# Adapted from https://github.com/python/cpython/blob/a5eeb832c2bbbd6ce1e9d545a553de926af468d5/Lib/test/test_monitoring.py#L670-L682
import sys
TEST_TOOL = 2
E = sys.monitoring.events
INSTRUMENTED_EVENTS = [
(E.PY_START, "start"),
# (E.PY_RETURN, "return"), # Uncomment this line leads to different behavior
]
class CounterWithDisable:
def __init__(self):
self.disable = False
self.count = 0
def __call__(self, *args):
print("cb", self)
self.count += 1
if self.disable:
return sys.monitoring.DISABLE
def foo(x):
return x + 1
def call_foo(x):
yield 2 * foo(x + 5)
def test():
sys.monitoring.use_tool_id(TEST_TOOL, "test")
for event, name in INSTRUMENTED_EVENTS:
print("Event", name)
try:
counter = CounterWithDisable()
counter.disable = True
sys.monitoring.register_callback(TEST_TOOL, event, counter)
sys.monitoring.set_events(TEST_TOOL, event)
list(call_foo(1))
print("counter.count", counter.count)
assert (counter.count < 4)
finally:
sys.monitoring.set_events(TEST_TOOL, 0)
sys.monitoring.register_callback(TEST_TOOL, event, None)
sys.monitoring.free_tool_id(TEST_TOOL)
print("First run".center(80, '='))
test()
print("Second run".center(80, '='))
test()
The above script prints:
===================================First run====================================
Event start
cb <__main__.CounterWithDisable object at 0x10944c0b0>
cb <__main__.CounterWithDisable object at 0x10944c0b0>
counter.count 2
===================================Second run===================================
Event start
counter.count 0
The first run "leaks" the disabled callback to the second run.
If I uncomment the line:
# (E.PY_RETURN, "return"), # Uncomment this line leads to different behavior
The script will print:
===================================First run====================================
Event start
cb <__main__.CounterWithDisable object at 0x10e34c1d0>
cb <__main__.CounterWithDisable object at 0x10e34c1d0>
counter.count 2
Event return
cb <__main__.CounterWithDisable object at 0x10e34c200>
cb <__main__.CounterWithDisable object at 0x10e34c200>
counter.count 2
===================================Second run===================================
Event start
cb <__main__.CounterWithDisable object at 0x10e34c2f0>
cb <__main__.CounterWithDisable object at 0x10e34c2f0>
counter.count 2
Event return
cb <__main__.CounterWithDisable object at 0x10e34c1d0>
cb <__main__.CounterWithDisable object at 0x10e34c1d0>
counter.count 2
It stops the "leaking".
This problem can be workarounded by calling sys.monitoring.restart_events() at the end of test(). But, it is not clear if it is necessary. This cpython test: https://github.com/python/cpython/blob/a5eeb832c2bbbd6ce1e9d545a553de926af468d5/Lib/test/test_monitoring.py#L670-L682
does not use sys.monitoring.restart_events().
CPython versions tested on:
3.12
Operating systems tested on:
Linux, macOS
Guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Direção de pesquisa
Comece executando o reproducer no CPython 3.12 e compare seu comportamento com Lib/test/test_monitoring.py nas linhas referenciadas. Rastreie como sys.monitoring.DISABLE persiste entre execuções de test() e como restart_events() altera esse comportamento. O trabalho estará concluído quando o ciclo de vida pretendido do callback estiver estabelecido, coberto por um teste de regressão, e a reutilização confusa estiver resolvida ou documentada.
Escrita pelo modelo de indexação a partir do texto da issue.
Avaliação
- Stack de tecnologia
- python
- Domínio
- devtools
- Tipo de issue
- Bug
- Dificuldade
- 4/5
- Tempo estimado
- 3-5 dias
- Status de atividade
- Estagnada
- Clareza
- Razoavelmente clara
- Facilidade para iniciantes
- 35/100