Skip to content

Commit

Permalink
feat: allow custom logger name for slot exception handler
Browse files Browse the repository at this point in the history
  • Loading branch information
komima authored and LKajan committed May 21, 2024
1 parent b05317c commit 6e29af2
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 20 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

- Feat: Support custom logger names for `log_if_fails` decorator

## [0.4.1] - 2024-2-1

- Fix: Fix submodule usage detection when installed as an embedded dependency
Expand Down
47 changes: 30 additions & 17 deletions tools/decorations.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,48 @@
__email__ = "[email protected]"
__revision__ = "$Format:%H$"

from typing import Any, Callable
from typing import Any, Callable, Optional

from .exceptions import QgsPluginException
from .i18n import tr
from .messages import MsgBar
from .messages import MessageBarLogger
from .tasks import FunctionTask


def log_if_fails(fn: Callable) -> Callable:
def log_if_fails(
fn: Optional[Callable] = None, /, *, logger_name: str = __name__
) -> Callable:
"""
Use this as a decorator with functions and methods that
might throw uncaught exceptions.
"""
from functools import wraps

@wraps(fn)
def wrapper(*args: Any, **kwargs: Any) -> None: # noqa: ANN001
try:
# Qt injects False into some signals
if args[1:] != (False,):
fn(*args, **kwargs)
else:
fn(*args[:-1], **kwargs)
except QgsPluginException as e:
MsgBar.exception(e, **e.bar_msg, stack_info=True)
except Exception as e:
MsgBar.exception(tr("Unhandled exception occurred"), e, stack_info=True)

return wrapper
# caller is at depth 3 (MessageBarLogger log call, this function, actual call)
message_bar = MessageBarLogger(logger_name, stack_level=3)

def decorator(fn: Callable) -> Callable:
@wraps(fn)
def wrapper(*args: Any, **kwargs: Any) -> None: # noqa: ANN001
try:
# Qt injects False into some signals
if args[1:] != (False,):
fn(*args, **kwargs)
else:
fn(*args[:-1], **kwargs)
except QgsPluginException as e:
message_bar.exception(e, **e.bar_msg, stack_info=True)
except Exception as e:
message_bar.exception(
tr("Unhandled exception occurred"), e, stack_info=True
)

return wrapper

if fn is None:
return decorator

return decorator(fn)


def taskify(fn: Callable) -> Callable:
Expand Down
12 changes: 9 additions & 3 deletions tools/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ class MessageBarLogger:
Setup with a logger name that has a message bar set.
"""

def __init__(self, logger_name: str) -> None:
def __init__(self, logger_name: str, stack_level: int = 2) -> None:
self._logger = logging.getLogger(logger_name)
self._logger_kwargs: Dict[str, Any] = (
{}
if sys.version_info.major == 3 and sys.version_info.minor < 8
else {"stacklevel": 2}
else {"stacklevel": stack_level}
)

def info(
Expand Down Expand Up @@ -148,10 +148,16 @@ def exception(
:param exc_info: Exception of handled exception for capturing traceback
:param stack_info: Whether to include stack info
"""
self._logger.exception(
# for some reason using logger.exception will essentially have extra stack level
# even though its not visible on the printed stack (possibly due to exception
# being a simple helper which calls error internally). use plain error here to
# have same effective stacklevel on both actual log records. possibly related
# https://github.com/python/cpython/issues/89334 has been fixed in 3.11+
self._logger.error(
str(message),
extra=bar_msg(details, duration, success),
stack_info=stack_info,
exc_info=True,
**self._logger_kwargs,
)
if details != "":
Expand Down

0 comments on commit 6e29af2

Please sign in to comment.