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 cmd_helper
15 from pylib
import constants
16 from pylib
.device
import device_errors
17 from pylib
.utils
import reraiser_thread
18 from pylib
.utils
import timeout_retry
20 # TODO(jbudorick) Remove once the DeviceUtils implementations are no longer
21 # backed by AndroidCommands / android_testrunner.
22 sys
.path
.append(os
.path
.join(constants
.DIR_SOURCE_ROOT
, 'third_party',
23 'android_testrunner'))
24 import errors
as old_errors
26 DEFAULT_TIMEOUT_ATTR
= '_default_timeout'
27 DEFAULT_RETRIES_ATTR
= '_default_retries'
30 def _TimeoutRetryWrapper(f
, timeout_func
, retries_func
, pass_values
=False):
31 """ Wraps a funcion with timeout and retry handling logic.
34 f: The function to wrap.
35 timeout_func: A callable that returns the timeout value.
36 retries_func: A callable that returns the retries value.
37 pass_values: If True, passes the values returned by |timeout_func| and
38 |retries_func| to the wrapped function as 'timeout' and
39 'retries' kwargs, respectively.
44 def TimeoutRetryWrapper(*args
, **kwargs
):
45 timeout
= timeout_func(*args
, **kwargs
)
46 retries
= retries_func(*args
, **kwargs
)
48 kwargs
['timeout'] = timeout
49 kwargs
['retries'] = retries
51 return f(*args
, **kwargs
)
53 if isinstance(threading
.current_thread(),
54 timeout_retry
.TimeoutRetryThread
):
57 return timeout_retry
.Run(impl
, timeout
, retries
)
58 except old_errors
.WaitForResponseTimedOutError
as e
:
59 raise device_errors
.CommandTimeoutError(str(e
)), None, (
61 except old_errors
.DeviceUnresponsiveError
as e
:
62 raise device_errors
.DeviceUnreachableError(str(e
)), None, (
64 except reraiser_thread
.TimeoutError
as e
:
65 raise device_errors
.CommandTimeoutError(str(e
)), None, (
67 except cmd_helper
.TimeoutError
as e
:
68 raise device_errors
.CommandTimeoutError(str(e
)), None, (
70 return TimeoutRetryWrapper
73 def WithTimeoutAndRetries(f
):
74 """A decorator that handles timeouts and retries.
76 'timeout' and 'retries' kwargs must be passed to the function.
79 f: The function to decorate.
81 The decorated function.
83 get_timeout
= lambda *a
, **kw
: kw
['timeout']
84 get_retries
= lambda *a
, **kw
: kw
['retries']
85 return _TimeoutRetryWrapper(f
, get_timeout
, get_retries
)
88 def WithExplicitTimeoutAndRetries(timeout
, retries
):
89 """Returns a decorator that handles timeouts and retries.
91 The provided |timeout| and |retries| values are always used.
94 timeout: The number of seconds to wait for the decorated function to
96 retries: The number of times the decorated function should be retried on
102 get_timeout
= lambda *a
, **kw
: timeout
103 get_retries
= lambda *a
, **kw
: retries
104 return _TimeoutRetryWrapper(f
, get_timeout
, get_retries
)
108 def WithTimeoutAndRetriesDefaults(default_timeout
, default_retries
):
109 """Returns a decorator that handles timeouts and retries.
111 The provided |default_timeout| and |default_retries| values are used only
112 if timeout and retries values are not provided.
115 default_timeout: The number of seconds to wait for the decorated function
116 to return. Only used if a 'timeout' kwarg is not passed
117 to the decorated function.
118 default_retries: The number of times the decorated function should be
119 retried on failure. Only used if a 'retries' kwarg is not
120 passed to the decorated function.
122 The actual decorator.
125 get_timeout
= lambda *a
, **kw
: kw
.get('timeout', default_timeout
)
126 get_retries
= lambda *a
, **kw
: kw
.get('retries', default_retries
)
127 return _TimeoutRetryWrapper(f
, get_timeout
, get_retries
, pass_values
=True)
131 def WithTimeoutAndRetriesFromInstance(
132 default_timeout_name
=DEFAULT_TIMEOUT_ATTR
,
133 default_retries_name
=DEFAULT_RETRIES_ATTR
):
134 """Returns a decorator that handles timeouts and retries.
136 The provided |default_timeout_name| and |default_retries_name| are used to
137 get the default timeout value and the default retries value from the object
138 instance if timeout and retries values are not provided.
140 Note that this should only be used to decorate methods, not functions.
143 default_timeout_name: The name of the default timeout attribute of the
145 default_retries_name: The name of the default retries attribute of the
148 The actual decorator.
151 def get_timeout(inst
, *_args
, **kwargs
):
152 return kwargs
.get('timeout', getattr(inst
, default_timeout_name
))
153 def get_retries(inst
, *_args
, **kwargs
):
154 return kwargs
.get('retries', getattr(inst
, default_retries_name
))
155 return _TimeoutRetryWrapper(f
, get_timeout
, get_retries
, pass_values
=True)