Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/backoff/_common.py: 22%
65 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:35 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:35 +0000
1# coding:utf-8
3import functools
4import logging
5import sys
6import traceback
7import warnings
10# Use module-specific logger with a default null handler.
11_logger = logging.getLogger('backoff')
12_logger.addHandler(logging.NullHandler()) # pragma: no cover
13_logger.setLevel(logging.INFO)
16# Evaluate arg that can be either a fixed value or a callable.
17def _maybe_call(f, *args, **kwargs):
18 if callable(f):
19 try:
20 return f(*args, **kwargs)
21 except TypeError:
22 return f
23 else:
24 return f
27def _init_wait_gen(wait_gen, wait_gen_kwargs):
28 kwargs = {k: _maybe_call(v) for k, v in wait_gen_kwargs.items()}
29 initialized = wait_gen(**kwargs)
30 initialized.send(None) # Initialize with an empty send
31 return initialized
34def _next_wait(wait, send_value, jitter, elapsed, max_time):
35 value = wait.send(send_value)
36 try:
37 if jitter is not None:
38 seconds = jitter(value)
39 else:
40 seconds = value
41 except TypeError:
42 warnings.warn(
43 "Nullary jitter function signature is deprecated. Use "
44 "unary signature accepting a wait value in seconds and "
45 "returning a jittered version of it.",
46 DeprecationWarning,
47 stacklevel=2,
48 )
50 seconds = value + jitter()
52 # don't sleep longer than remaining allotted max_time
53 if max_time is not None:
54 seconds = min(seconds, max_time - elapsed)
56 return seconds
59def _prepare_logger(logger):
60 if isinstance(logger, str):
61 logger = logging.getLogger(logger)
62 return logger
65# Configure handler list with user specified handler and optionally
66# with a default handler bound to the specified logger.
67def _config_handlers(
68 user_handlers, *, default_handler=None, logger=None, log_level=None
69):
70 handlers = []
71 if logger is not None:
72 assert log_level is not None, "Log level is not specified"
73 # bind the specified logger to the default log handler
74 log_handler = functools.partial(
75 default_handler, logger=logger, log_level=log_level
76 )
77 handlers.append(log_handler)
79 if user_handlers is None:
80 return handlers
82 # user specified handlers can either be an iterable of handlers
83 # or a single handler. either way append them to the list.
84 if hasattr(user_handlers, '__iter__'):
85 # add all handlers in the iterable
86 handlers += list(user_handlers)
87 else:
88 # append a single handler
89 handlers.append(user_handlers)
91 return handlers
94# Default backoff handler
95def _log_backoff(details, logger, log_level):
96 msg = "Backing off %s(...) for %.1fs (%s)"
97 log_args = [details['target'].__name__, details['wait']]
99 exc_typ, exc, _ = sys.exc_info()
100 if exc is not None:
101 exc_fmt = traceback.format_exception_only(exc_typ, exc)[-1]
102 log_args.append(exc_fmt.rstrip("\n"))
103 else:
104 log_args.append(details['value'])
105 logger.log(log_level, msg, *log_args)
108# Default giveup handler
109def _log_giveup(details, logger, log_level):
110 msg = "Giving up %s(...) after %d tries (%s)"
111 log_args = [details['target'].__name__, details['tries']]
113 exc_typ, exc, _ = sys.exc_info()
114 if exc is not None:
115 exc_fmt = traceback.format_exception_only(exc_typ, exc)[-1]
116 log_args.append(exc_fmt.rstrip("\n"))
117 else:
118 log_args.append(details['value'])
120 logger.log(log_level, msg, *log_args)