Исключение цвета из Python на терминале

Есть ли простой способ получить сообщение о том, что исключение будет окрашено в командной строке? Например

def g():    f()
def f():    1/0
g()

Дает ошибку

Traceback (most recent call last):
  File "test.py", line 3, in <module>
    g()
  File "test.py", line 1, in g
    def g():    f()
  File "test.py", line 2, in f
    def f():    1/0
ZeroDivisionError: integer division or modulo by zero

Я хотел бы, чтобы " целочисленное деление или по модулю нуль" было окрашено или выделено на терминале, чтобы я мог быстро выбрать его из длинной трассировки (только для Linux). В идеале я бы не хотел писать пользовательский класс для каждого Exception, но каким-то образом улавливал и форматировал все виды.

EDIT: Вопрос, связанный с комментариями, содержит примеры того, как решить проблему с внешним программным обеспечением, но меня интересует внутреннее решение Python.

Ответ 1

Вы можете назначить пользовательскую функцию обработчику sys.excepthook. Функция вызывается всякий раз, когда есть необработанное исключение (например, выходящее из интерпретатора).

def set_highlighted_excepthook():
    import sys, traceback
    from pygments import highlight
    from pygments.lexers import get_lexer_by_name
    from pygments.formatters import TerminalFormatter

    lexer = get_lexer_by_name("pytb" if sys.version_info.major < 3 else "py3tb")
    formatter = TerminalFormatter()

    def myexcepthook(type, value, tb):
        tbtext = ''.join(traceback.format_exception(type, value, tb))
        sys.stderr.write(highlight(tbtext, lexer, formatter))

    sys.excepthook = myexcepthook

set_highlighted_excepthook()

Эта версия использует библиотеку pygments для преобразования текста трассировки в текст, отформатированный с раскраской ANSI, перед записью его в stderr.

Кто-то превратил это в проект, который обнаруживает поддержку терминала и позволяет вам установить стиль фрагментов, см. colored-traceback.py.

Ответ 2

Найден другой способ сделать это с помощью модуля IPython, который, скорее всего, зависит от того, что все уже установлены:

from IPython.core.ultratb import ColorTB
c = ColorTB()
exc = sys.exc_info()
print(''.join(c.structured_traceback(*exc)))

Ответ 3

Посмотрите colorama (или любой другой раскрашивающий) модуль. Затем вы можете обернуть все приложение:

import traceback
from colorama import Fore, init
init( )

try:
    // your app
except Exception:
    print Fore.RED + traceback.format_exc( ) + Fore.RESET
    // possibly raise again or log to db

Ответ 4

Это принимает решение @freakish shared и делает раскраску частью исключения, а не требует от пользователя добавлять цвет к каждому сообщению исключения. Очевидно, что он работает только для пользовательских исключений, поэтому он может быть не совсем тем, что искал OP.

from colorama import Fore, init
init()

class Error (Exception):
    def __init__ (self, message):
        super().__init__(Fore.RED + message)

class BadConfigFile (Error):
    pass

raise BadConfigFile("some error message")

Это напечатает трассировку с "некоторым сообщением об ошибке" красным. Наличие "Error" в качестве базового класса означает, что вы можете создавать другие исключения, которые будут наследовать раскраску сообщения.