Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/logger/errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class LoggerError(Exception):
"""Base class for package exceptions."""


class UnknownLogLevelError(LoggerError):
"""Raised when a specified log level doesn't match any known log level."""

def __init__(self, invalid_value: str, valid_values: list) -> None:
"""Raise the error with correct message."""
super().__init__(
f"Invalid log level '{invalid_value}'. Must be one of: {valid_values}",
)


class LoggerNotSetError(LoggerError):
"""Raised when a logger is not set on the application."""

def __init__(self) -> None:
"""Raise the error with correct message."""
super().__init__("Logger not set")
5 changes: 3 additions & 2 deletions src/logger/loggable_mixin.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .contract import LoggerContract
from .errors import LoggerNotSetError


class LoggableMixin:
Expand All @@ -16,10 +17,10 @@ def logger(self) -> LoggerContract:
The configured logger instance.

Raises:
RuntimeError: If logger has not been set.
LoggerNotSetError: If logger has not been set.
"""
if self._logger is None:
raise RuntimeError("Logger not set")
raise LoggerNotSetError
return self._logger

@logger.setter
Expand Down
8 changes: 4 additions & 4 deletions src/logger/loglevel.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from enum import IntEnum
from typing import Self

from .errors import UnknownLogLevelError


class LogLevel(IntEnum):
"""Represents the different log levels."""
Expand All @@ -23,12 +25,10 @@ def from_str(cls, value: str) -> Self:
LogLevel enum value.

Raises:
ValueError: If the string doesn't match any log level.
UnknownLogLevelError: If the string doesn't match any log level.
"""
try:
return cls[value.upper()]
except KeyError as e:
valid_values = [e.name for e in cls]
raise ValueError(
f"Invalid log level '{value}'. Must be one of: {valid_values}",
) from e
raise UnknownLogLevelError(value, valid_values) from e
3 changes: 2 additions & 1 deletion tests/logger/loggable_mixin_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import pytest

from src.logger.errors import LoggerNotSetError
from src.logger.loggable_mixin import LoggableMixin


Expand All @@ -27,7 +28,7 @@ def test_logger_not_set(self, loggable: LoggableMixin) -> None:
Args:
loggable: Fresh LoggableMixin instance without a logger set
"""
with pytest.raises(RuntimeError, match="Logger not set"):
with pytest.raises(LoggerNotSetError, match="Logger not set"):
_ = loggable.logger

def test_logger_set(self, loggable: LoggableMixin, mock_logger: Mock) -> None:
Expand Down
3 changes: 2 additions & 1 deletion tests/logger/loglevel_test.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pytest

from src.logger.errors import UnknownLogLevelError
from src.logger.loglevel import LogLevel


Expand Down Expand Up @@ -29,5 +30,5 @@ def test_from_str_invalid(self) -> None:
- The error message contains "Invalid log level" to help with debugging
- The validation prevents incorrect string values from being accepted
"""
with pytest.raises(ValueError, match="Invalid log level"):
with pytest.raises(UnknownLogLevelError, match="Invalid log level"):
LogLevel.from_str("INVALID")
3 changes: 2 additions & 1 deletion tests/logger/loguru_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ def test_exception_log(
- Additional context is preserved
"""
try:
raise ValueError("Sample exception") # noqa: TRY301
msg = "Sample exception"
raise ValueError(msg) # noqa: TRY301
except ValueError as exc:
loguru_logger.exception(
"An error occurred",
Expand Down