Skip to content

Commit

Permalink
Add unit tests for theoretical "UnboundLocalError"
Browse files Browse the repository at this point in the history
  • Loading branch information
Delgan committed Oct 2, 2023
1 parent 14da892 commit a48a0e2
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 24 deletions.
44 changes: 22 additions & 22 deletions loguru/_better_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,31 +455,31 @@ def _format_exception(
# 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.
error_message_index = 0
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:
exception_type, exception_value = error_message.split(":", 1)
exception_type = self._theme["exception_type"].format(exception_type)
exception_value = self._theme["exception_value"].format(exception_value)
error_message = exception_type + ":" + exception_value
else:
error_message = self._theme["exception_type"].format(error_message)
no_indented_indexes = (i for i, p in enumerate(exception_only) if not p.startswith(" "))
error_message_index = next(no_indented_indexes, None)

if self._diagnose and frames:
if issubclass(exc_type, AssertionError) and not str(exc_value) and final_source:
if self._colorize:
final_source = self._syntax_highlighter.highlight(final_source)
error_message += ": " + final_source
if error_message_index is not None:
# Remove final new line temporarily.
error_message = exception_only[error_message_index][:-1]

if self._colorize:
if ":" in error_message:
exception_type, exception_value = error_message.split(":", 1)
exception_type = self._theme["exception_type"].format(exception_type)
exception_value = self._theme["exception_value"].format(exception_value)
error_message = exception_type + ":" + exception_value
else:
error_message = self._theme["exception_type"].format(error_message)

if self._diagnose and frames:
if issubclass(exc_type, AssertionError) and not str(exc_value) and final_source:
if self._colorize:
final_source = self._syntax_highlighter.highlight(final_source)
error_message += ": " + final_source

error_message = "\n" + error_message
error_message = "\n" + error_message

exception_only[error_message_index] = error_message + "\n"
exception_only[error_message_index] = error_message + "\n"

if is_first:
yield self._prefix
Expand Down
41 changes: 39 additions & 2 deletions tests/test_exceptions_formatting.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
import re
import subprocess
import sys
import traceback
from unittest.mock import MagicMock

import pytest

from loguru import logger


def normalize(exception):
"""Normalize exception output for reproducible test cases"""
Expand Down Expand Up @@ -257,8 +261,6 @@ def test_exception_modern(filename, minimum_python_version):
def test_group_exception_using_backport(writer):
from exceptiongroup import ExceptionGroup

from loguru import logger

logger.add(writer, backtrace=True, diagnose=True, colorize=False, format="")

try:
Expand All @@ -267,3 +269,38 @@ def test_group_exception_using_backport(writer):
logger.exception("")

assert writer.read().strip().startswith("+ Exception Group Traceback (most recent call last):")


def test_invalid_format_exception_only_no_output(writer, monkeypatch):
logger.add(writer, backtrace=True, diagnose=True, colorize=False, format="")

with monkeypatch.context() as context:
context.setattr(traceback, "format_exception_only", lambda _e, _v: [])
error = ValueError(0)
logger.opt(exception=error).error("Error")

assert writer.read() == "\n"


def test_invalid_format_exception_only_indented_error_message(writer, monkeypatch):
logger.add(writer, backtrace=True, diagnose=True, colorize=False, format="")

with monkeypatch.context() as context:
context.setattr(traceback, "format_exception_only", lambda _e, _v: [" ValueError: 0\n"])
error = ValueError(0)
logger.opt(exception=error).error("Error")

assert writer.read() == "\n ValueError: 0\n"


@pytest.mark.skipif(sys.version_info < (3, 11), reason="No builtin GroupedException")
def test_invalid_grouped_exception_no_exceptions(writer):
error = MagicMock(spec=ExceptionGroup)
error.__cause__ = None
error.__context__ = None
error.__traceback__ = None

logger.add(writer, backtrace=True, diagnose=True, colorize=False, format="")
logger.opt(exception=error).error("Error")

assert writer.read().strip().startswith("| unittest.mock.MagicMock:")

0 comments on commit a48a0e2

Please sign in to comment.