From 4d9ebbb64029c272d7239d380604a219c4a96aa9 Mon Sep 17 00:00:00 2001 From: aragaer Date: Tue, 26 Sep 2023 19:16:00 +0300 Subject: [PATCH] Add optional label to BaseRetrying class If label is set it will be used instead of a function name in before_sleep_log --- .../retrying-label-62a5384cd3a49859.yaml | 3 +++ tenacity/__init__.py | 19 ++++++++++++++++++- tenacity/after.py | 8 ++------ tenacity/before.py | 8 ++------ tenacity/before_sleep.py | 10 ++-------- 5 files changed, 27 insertions(+), 21 deletions(-) create mode 100644 releasenotes/notes/retrying-label-62a5384cd3a49859.yaml diff --git a/releasenotes/notes/retrying-label-62a5384cd3a49859.yaml b/releasenotes/notes/retrying-label-62a5384cd3a49859.yaml new file mode 100644 index 00000000..44215ddf --- /dev/null +++ b/releasenotes/notes/retrying-label-62a5384cd3a49859.yaml @@ -0,0 +1,3 @@ +--- +features: + - "Add optional label to Retrying class to be shown in logs" diff --git a/tenacity/__init__.py b/tenacity/__init__.py index 9a5fa41a..5be83dd9 100644 --- a/tenacity/__init__.py +++ b/tenacity/__init__.py @@ -79,6 +79,8 @@ from .before_sleep import before_sleep_log # noqa from .before_sleep import before_sleep_nothing # noqa +from ._utils import get_callback_name + try: import tornado except ImportError: @@ -199,6 +201,7 @@ def __init__( reraise: bool = False, retry_error_cls: t.Type[RetryError] = RetryError, retry_error_callback: t.Optional[t.Callable[["RetryCallState"], t.Any]] = None, + label: t.Optional[str] = None, ): self.sleep = sleep self.stop = stop @@ -211,6 +214,7 @@ def __init__( self._local = threading.local() self.retry_error_cls = retry_error_cls self.retry_error_callback = retry_error_callback + self.label = label def copy( self, @@ -224,6 +228,7 @@ def copy( reraise: t.Union[bool, object] = _unset, retry_error_cls: t.Union[t.Type[RetryError], object] = _unset, retry_error_callback: t.Union[t.Optional[t.Callable[["RetryCallState"], t.Any]], object] = _unset, + label: t.Optional[str] = _unset, ) -> "BaseRetrying": """Copy this object with some parameters changed if needed.""" return self.__class__( @@ -237,6 +242,7 @@ def copy( reraise=_first_set(reraise, self.reraise), retry_error_cls=_first_set(retry_error_cls, self.retry_error_cls), retry_error_callback=_first_set(retry_error_callback, self.retry_error_callback), + label=_first_set(label, self.label), ) def __repr__(self) -> str: @@ -247,7 +253,8 @@ def __repr__(self) -> str: f"sleep={self.sleep}, " f"retry={self.retry}, " f"before={self.before}, " - f"after={self.after})>" + f"after={self.after}, " + f"label={self.label})>" ) @property @@ -458,6 +465,16 @@ def seconds_since_start(self) -> t.Optional[float]: return None return self.outcome_timestamp - self.start_time + @property + def fn_label(self): + if self.retry_object.label is None: + if self.fn is None: + return "" + else: + return get_callback_name(self.fn) + else: + return self.retry_object.label + def prepare_for_next_attempt(self) -> None: self.outcome = None self.outcome_timestamp = None diff --git a/tenacity/after.py b/tenacity/after.py index aa3cc9df..907539f9 100644 --- a/tenacity/after.py +++ b/tenacity/after.py @@ -36,14 +36,10 @@ def after_log( """After call strategy that logs to some logger the finished attempt.""" def log_it(retry_state: "RetryCallState") -> None: - if retry_state.fn is None: - # NOTE(sileht): can't really happen, but we must please mypy - fn_name = "" - else: - fn_name = _utils.get_callback_name(retry_state.fn) + label = retry_state.fn_label logger.log( log_level, - f"Finished call to '{fn_name}' " + f"Finished call to '{label}' " f"after {sec_format % retry_state.seconds_since_start}(s), " f"this was the {_utils.to_ordinal(retry_state.attempt_number)} time calling it.", ) diff --git a/tenacity/before.py b/tenacity/before.py index 9284f7ae..94fdbc4f 100644 --- a/tenacity/before.py +++ b/tenacity/before.py @@ -32,14 +32,10 @@ def before_log(logger: "logging.Logger", log_level: int) -> typing.Callable[["Re """Before call strategy that logs to some logger the attempt.""" def log_it(retry_state: "RetryCallState") -> None: - if retry_state.fn is None: - # NOTE(sileht): can't really happen, but we must please mypy - fn_name = "" - else: - fn_name = _utils.get_callback_name(retry_state.fn) + label = retry_state.fn_label logger.log( log_level, - f"Starting call to '{fn_name}', " + f"Starting call to '{label}', " f"this is the {_utils.to_ordinal(retry_state.attempt_number)} time calling it.", ) diff --git a/tenacity/before_sleep.py b/tenacity/before_sleep.py index 279a21eb..0ebcea85 100644 --- a/tenacity/before_sleep.py +++ b/tenacity/before_sleep.py @@ -16,8 +16,6 @@ import typing -from tenacity import _utils - if typing.TYPE_CHECKING: import logging @@ -56,15 +54,11 @@ def log_it(retry_state: "RetryCallState") -> None: verb, value = "returned", retry_state.outcome.result() local_exc_info = False # exc_info does not apply when no exception - if retry_state.fn is None: - # NOTE(sileht): can't really happen, but we must please mypy - fn_name = "" - else: - fn_name = _utils.get_callback_name(retry_state.fn) + label = retry_state.fn_label logger.log( log_level, - f"Retrying {fn_name} " f"in {retry_state.next_action.sleep} seconds as it {verb} {value}.", + f"Retrying {label} " f"in {retry_state.next_action.sleep} seconds as it {verb} {value}.", exc_info=local_exc_info, )