1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
6 Function/method decorators that provide timeout and retry logic.
14 from pylib
import constants
15 from pylib
.device
import device_errors
16 from pylib
.utils
import reraiser_thread
17 from pylib
.utils
import timeout_retry
19 # TODO(jbudorick) Remove once the DeviceUtils implementations are no longer
20 # backed by AndroidCommands / android_testrunner.
21 sys
.path
.append(os
.path
.join(constants
.DIR_SOURCE_ROOT
, 'third_party',
22 'android_testrunner'))
23 import errors
as old_errors
25 DEFAULT_TIMEOUT_ATTR
= '_default_timeout'
26 DEFAULT_RETRIES_ATTR
= '_default_retries'
29 def _TimeoutRetryWrapper(f
, timeout_func
, retries_func
, pass_values
=False):
30 """ Wraps a funcion with timeout and retry handling logic.
33 f: The function to wrap.
34 timeout_func: A callable that returns the timeout value.
35 retries_func: A callable that returns the retries value.
36 pass_values: If True, passes the values returned by |timeout_func| and
37 |retries_func| to the wrapped function as 'timeout' and
38 'retries' kwargs, respectively.
43 def TimeoutRetryWrapper(*args
, **kwargs
):
44 timeout
= timeout_func(*args
, **kwargs
)
45 retries
= retries_func(*args
, **kwargs
)
47 kwargs
['timeout'] = timeout
48 kwargs
['retries'] = retries
50 return f(*args
, **kwargs
)
52 if isinstance(threading
.current_thread(),
53 timeout_retry
.TimeoutRetryThread
):
56 return timeout_retry
.Run(impl
, timeout
, retries
)
57 except old_errors
.WaitForResponseTimedOutError
as e
:
58 raise device_errors
.CommandTimeoutError(str(e
)), None, (
60 except old_errors
.DeviceUnresponsiveError
as e
:
61 raise device_errors
.DeviceUnreachableError(str(e
)), None, (
63 except reraiser_thread
.TimeoutError
as e
:
64 raise device_errors
.CommandTimeoutError(str(e
)), None, (
66 return TimeoutRetryWrapper
69 def WithTimeoutAndRetries(f
):
70 """A decorator that handles timeouts and retries.
72 'timeout' and 'retries' kwargs must be passed to the function.
75 f: The function to decorate.
77 The decorated function.
79 get_timeout
= lambda *a
, **kw
: kw
['timeout']
80 get_retries
= lambda *a
, **kw
: kw
['retries']
81 return _TimeoutRetryWrapper(f
, get_timeout
, get_retries
)
84 def WithExplicitTimeoutAndRetries(timeout
, retries
):
85 """Returns a decorator that handles timeouts and retries.
87 The provided |timeout| and |retries| values are always used.
90 timeout: The number of seconds to wait for the decorated function to
92 retries: The number of times the decorated function should be retried on
98 get_timeout
= lambda *a
, **kw
: timeout
99 get_retries
= lambda *a
, **kw
: retries
100 return _TimeoutRetryWrapper(f
, get_timeout
, get_retries
)
104 def WithTimeoutAndRetriesDefaults(default_timeout
, default_retries
):
105 """Returns a decorator that handles timeouts and retries.
107 The provided |default_timeout| and |default_retries| values are used only
108 if timeout and retries values are not provided.
111 default_timeout: The number of seconds to wait for the decorated function
112 to return. Only used if a 'timeout' kwarg is not passed
113 to the decorated function.
114 default_retries: The number of times the decorated function should be
115 retried on failure. Only used if a 'retries' kwarg is not
116 passed to the decorated function.
118 The actual decorator.
121 get_timeout
= lambda *a
, **kw
: kw
.get('timeout', default_timeout
)
122 get_retries
= lambda *a
, **kw
: kw
.get('retries', default_retries
)
123 return _TimeoutRetryWrapper(f
, get_timeout
, get_retries
, pass_values
=True)
127 def WithTimeoutAndRetriesFromInstance(
128 default_timeout_name
=DEFAULT_TIMEOUT_ATTR
,
129 default_retries_name
=DEFAULT_RETRIES_ATTR
):
130 """Returns a decorator that handles timeouts and retries.
132 The provided |default_timeout_name| and |default_retries_name| are used to
133 get the default timeout value and the default retries value from the object
134 instance if timeout and retries values are not provided.
136 Note that this should only be used to decorate methods, not functions.
139 default_timeout_name: The name of the default timeout attribute of the
141 default_retries_name: The name of the default retries attribute of the
144 The actual decorator.
147 def get_timeout(inst
, *_args
, **kwargs
):
148 return kwargs
.get('timeout', getattr(inst
, default_timeout_name
))
149 def get_retries(inst
, *_args
, **kwargs
):
150 return kwargs
.get('retries', getattr(inst
, default_retries_name
))
151 return _TimeoutRetryWrapper(f
, get_timeout
, get_retries
, pass_values
=True)