Реализация Tcl bgerror в python

Это дополнительный вопрос от этого , где предлагается реализовать bgerror, чтобы фактически получить ответ на то, что пошло не так в фоновом режиме. Однако я немного запутался, поскольку я понимаю документацию, должно быть достаточно определить proc с именем bgerror, которое будет вызываться интерпретатором, не так ли?

Моя попытка ниже показывает, как я пытаюсь это реализовать, но безрезультатно.

import tkinter as tk

tcl = tk.Tk()
####work around for puts in python
def puts(inp):
    print(inp)

cmd = tcl.register(puts)
tcl.eval(
    'proc puts {args} {' +
        f'{cmd} [join $args " "]' +
    '}')
tcl.call('puts', 'test') #test puts

#attempt to implement bgerror 
tcl.eval('''
proc bgerror {message} {
    set timestamp [clock format [clock seconds]]
    puts "$timestamp: bgerror in $::argv '$message'"
}''')

#setup a failing proc
tcl.eval('''
after 500 {error "this is an error"}
''')
tcl.mainloop()

Кроме того, было бы неплохо узнать, правильный ли это вообще подход, поскольку в документации для новых приложений предлагается использовать interp bgerror. Но я снова в замешательстве, потому что, похоже, нет индикатора, где я мог бы найти path для этих вызовов, или они предназначены исключительно для дочернего переводчика?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
100
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

После небольшого исследования я обнаружил, что это (давно) нерешенная проблема в python. Сравните "Выпуск 639266". Чтобы обойти это, вы должны использовать createcommand, как показано в недавнем (2010 г.) обновленном разговоре.

Обновленный код выглядит так:

import tkinter as tk

tcl = tk.Tk()

#attempt to implement bgerror
def bgerr_handler(msg):
    print (msg, "<<")
tcl.tk.createcommand("bgerror", bgerr_handler)

#setup a failing proc
tcl.eval('''
after 500 {error "this is an error"}
''')
tcl.mainloop()

Обновлять: Они даже закрыли эту проблему на github с:

Этому уже 20 лет, а согласия по проблеме не было. Если есть проблема, которую нужно исправить, она будет поднята снова.

Также обратите внимание, что в самой документации указано, что:

Если вы пишете код, который будет использоваться другими как часть пакет или другую библиотеку, избегайте bgerror. Причина этого в том, что программист приложения может также захотеть определите bgerror или используйте другой код, который делает это и, следовательно, будет иметь проблемы с интеграцией вашего кода.

Однако в случае tkinter я бы сделал исключение из этой рекомендации, так как довольно редко разработчики Python хотят реализовать свой собственный tcl bgerror, и более вероятно, что они будут удивлены молчаливым игнорируемым исключением и столкнутся с «просто не работающим». код".

Определение фонового обработчика ошибок — это хорошо и рекомендуется для приложения, но не очень хорошо для библиотеки.

Donal Fellows 01.05.2023 13:21
Ответ принят как подходящий

В этом случае вам лучше использовать явную регистрацию вместо использования неявной регистрации на основе именования, так как это позволит вам получить доступ ко всей информации об ошибке (включая трассировку стека!), а не только к сообщению.

import tkinter
tcl = tkinter.Tcl()

# Fortunately, we can put the complex stuff in a function
def install_bgerror_handler(tcl, handler):
    def type_thunk(message, options):
        # Call internal command to convert Tcl dict to Python dict
        handler(message, tkinter._splitdict(tcl, options))
    tcl.createcommand(handler.__name__, type_thunk)
    tcl.call("interp", "bgerror", "", handler.__name__)

def bgerr_handler(message, options):
    print(message, "<<", options)

install_bgerror_handler(tcl, bgerr_handler)

# demonstrate with a background failure
tcl.eval('''
    after 500 {error "this is an error"}
''')
tcl.mainloop()

Сообщение, распечатываемое в этом случае: this is an error << {'code': '1', 'level': '0', 'errorstack': 'INNER {returnImm {this is an error} {}}', 'errorcode': 'NONE', 'errorinfo': 'this is an error\n while executing\n"error "this is an error""\n ("after" script)', 'errorline': '1'} Трассировка стека доступна в обработчике как options["errorinfo"]. errorcode и errorline тоже могут быть интересны. (Преобразование на основе kwargs оставлено в качестве упражнения, но имейте в виду, что набор ключей в этом словаре не является закрытым набором; более сложные ошибки могут включать ключи, не перечисленные выше.)

Рекомендуется проявлять особую осторожность, чтобы избежать фактического создания исключений из вашего обработчика. Все сработает, но, вероятно, это плохой план.

Я предположил, что использование __name__ подходит для создания имени. Для правильного производственного кода, вероятно, потребуется какая-то генерация символов, такая как то, что tkinter делает внутри для обратных вызовов.

Donal Fellows 01.05.2023 13:18

Я не уверен, зачем нужно генерировать уникальное имя. Это просто из-за осторожности, чтобы случайно не перезаписать обработчик, или для этого есть другая причина?

Thingamabobs 01.05.2023 13:30

Чисто из осторожности.

Donal Fellows 02.05.2023 13:24

Другие вопросы по теме

Кнопка tkinter в импортированном модуле: как обновить главное окно модуля
Tkinter — привязка клавиш клавиатуры к элементам/элементам на холсте
Почему tkinter (или черепаха) отсутствует или сломан? Разве это не должно быть частью стандартной библиотеки?
Приложение Tkinter деиконизируется при запуске из полноэкранного режима другого приложения (MacOS)
Настройка положения текста внутри customtkinter.CTkLabel с изображением
Генерировать функции, в которых есть более одной строки кода
Программа для копирования, переименования и вставки файлов. Ошибка tkinter listdir: путь должен быть строкой, байтами, os.Pathlike или None
Генератор судоку и решатель на питоне
Почему мое приложение customTkinter не использует .after? Он должен печатать «привет» каждые 10 миллисекунд
Создание базового калькулятора с помощью tkinter с использованием Python. Путаница при передаче возвращаемого значения между классами