From d70e7af93f6d19ee61e35dcd9de3d5cef66ae85a Mon Sep 17 00:00:00 2001 From: Delgan Date: Sat, 9 Sep 2023 16:34:49 +0200 Subject: [PATCH] Fix formatting of notes possible added to an Exception --- CHANGELOG.rst | 1 + loguru/_better_exceptions.py | 14 ++- tests/exceptions/output/modern/notes.txt | 117 +++++++++++++++++++++++ tests/exceptions/source/modern/notes.py | 43 +++++++++ tests/test_exceptions_formatting.py | 1 + 5 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 tests/exceptions/output/modern/notes.txt create mode 100644 tests/exceptions/source/modern/notes.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8d8bac98..9ed06198 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,7 @@ ============= - Add support for formatting of ``ExceptionGroup`` errors (`#805 `_). +- Fix formatting of possible ``__notes__`` attached to an ``Exception`` (`#980 `_). `0.7.1`_ (2023-09-04) diff --git a/loguru/_better_exceptions.py b/loguru/_better_exceptions.py index b05c77f2..f815ee89 100644 --- a/loguru/_better_exceptions.py +++ b/loguru/_better_exceptions.py @@ -441,7 +441,17 @@ def _format_exception( ) exception_only = traceback.format_exception_only(exc_type, exc_value) - error_message = exception_only[-1][:-1] # Remove last new line temporarily + # Determining the correct index for the "Exception: message" part in the formatted exception + # is challenging. This is because it might be preceded by multiple lines specific to + # "SyntaxError" or followed by various notes. However, we can make an educated guess based + # on the indentation; the preliminary context for "SyntaxError" is always indented, while + # the Exception itself is not. This allows us to identify the correct index for the + # exception message. + for error_message_index, part in enumerate(exception_only): # noqa: B007 + if not part.startswith(" "): + break + + error_message = exception_only[error_message_index][:-1] # Remove last new line temporarily if self._colorize: if ":" in error_message: @@ -460,7 +470,7 @@ def _format_exception( error_message = "\n" + error_message - exception_only[-1] = error_message + "\n" + exception_only[error_message_index] = error_message + "\n" if is_first: yield self._prefix diff --git a/tests/exceptions/output/modern/notes.txt b/tests/exceptions/output/modern/notes.txt new file mode 100644 index 00000000..5eae642f --- /dev/null +++ b/tests/exceptions/output/modern/notes.txt @@ -0,0 +1,117 @@ + +Traceback (most recent call last): + File "tests/exceptions/source/modern/notes.py", line 13, in + raise e +ValueError: invalid value +Note + +Traceback (most recent call last): + +> File "tests/exceptions/source/modern/notes.py", line 13, in  + raise e +  └ ValueError('invalid value') + +ValueError: invalid value +Note + +Traceback (most recent call last): + File "tests/exceptions/source/modern/notes.py", line 20, in + raise e +ValueError: invalid value +Note1 +Note2 +Note3 + + +Traceback (most recent call last): + +> File "tests/exceptions/source/modern/notes.py", line 20, in  + raise e +  └ ValueError('invalid value') + +ValueError: invalid value +Note1 +Note2 +Note3 + + + + Exception Group Traceback (most recent call last): + | File "tests/exceptions/source/modern/notes.py", line 27, in + | raise e + | ExceptionGroup: Grouped (2 sub-exceptions) + | Note 1 + | Note 2 + | Note 3 + +-+---------------- 1 ---------------- + | ValueError: 1 + +---------------- 2 ---------------- + | ValueError: 2 + +------------------------------------ + + + Exception Group Traceback (most recent call last): + | + | > File "tests/exceptions/source/modern/notes.py", line 27, in  + | raise e + |  └ ExceptionGroup('Grouped', [ValueError(1), ValueError(2)]) + | + | ExceptionGroup: Grouped (2 sub-exceptions) + | Note 1 + | Note 2 + | Note 3 + +-+---------------- 1 ---------------- + | ValueError: 1 + +---------------- 2 ---------------- + | ValueError: 2 + +------------------------------------ + +Traceback (most recent call last): + File "tests/exceptions/source/modern/notes.py", line 32, in + raise e +TabError: tab error +Note + +Traceback (most recent call last): + +> File "tests/exceptions/source/modern/notes.py", line 32, in  + raise e +  └ TabError('tab error') + +TabError: tab error +Note + +Traceback (most recent call last): + File "tests/exceptions/source/modern/notes.py", line 38, in + raise e + File "", line 1 + a = 7 * + ^ +SyntaxError: syntax error +Note 1 +Note 2 + +Traceback (most recent call last): + +> File "tests/exceptions/source/modern/notes.py", line 38, in  + raise e +  └ SyntaxError('syntax error', ('', 1, 8, 'a = 7 *\n', 1, 8)) + + File "", line 1 + a = 7 * + ^ + +SyntaxError: syntax error +Note 1 +Note 2 + +Traceback (most recent call last): + File "tests/exceptions/source/modern/notes.py", line 43, in + raise e +TypeError: type error + +Traceback (most recent call last): + +> File "tests/exceptions/source/modern/notes.py", line 43, in  + raise e +  └ TypeError('type error') + +TypeError: type error diff --git a/tests/exceptions/source/modern/notes.py b/tests/exceptions/source/modern/notes.py new file mode 100644 index 00000000..69cddfde --- /dev/null +++ b/tests/exceptions/source/modern/notes.py @@ -0,0 +1,43 @@ +from loguru import logger +import sys + + +logger.remove() +logger.add(sys.stderr, format="", diagnose=False, backtrace=False, colorize=False) +logger.add(sys.stderr, format="", diagnose=True, backtrace=True, colorize=True) + + +with logger.catch(): + e = ValueError("invalid value") + e.add_note("Note") + raise e + + +with logger.catch(): + e = ValueError("invalid value") + e.add_note("Note1") + e.add_note("Note2\nNote3\n") + raise e + + +with logger.catch(): + e = ExceptionGroup("Grouped", [ValueError(1), ValueError(2)]) + e.add_note("Note 1\nNote 2") + e.add_note("Note 3") + raise e + +with logger.catch(): + e = TabError("tab error") + e.add_note("Note") + raise e + +with logger.catch(): + e = SyntaxError("syntax error", ("", 1, 8, "a = 7 *\n", 1, 8)) + e.add_note("Note 1") + e.add_note("Note 2") + raise e + +with logger.catch(): + e = TypeError("type error") + e.__notes__ = None + raise e diff --git a/tests/test_exceptions_formatting.py b/tests/test_exceptions_formatting.py index e1c49362..b2f97b21 100644 --- a/tests/test_exceptions_formatting.py +++ b/tests/test_exceptions_formatting.py @@ -235,6 +235,7 @@ def test_exception_others(filename): ("walrus_operator", (3, 8)), ("match_statement", (3, 10)), ("exception_group_catch", (3, 11)), + ("notes", (3, 11)), ("grouped_simple", (3, 11)), ("grouped_nested", (3, 11)), ("grouped_with_cause_and_context", (3, 11)),