Add Apps.AppListSearchQueryLength UMA histogram.
[chromium-blink-merge.git] / build / android / pylib / device / decorators.py
blob73c13da8b09b9c0c2ffe6053f6fac529801ed997
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.
5 """
6 Function/method decorators that provide timeout and retry logic.
7 """
9 import functools
10 import os
11 import sys
12 import threading
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.
33 Args:
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.
40 Returns:
41 The wrapped function.
42 """
43 @functools.wraps(f)
44 def TimeoutRetryWrapper(*args, **kwargs):
45 timeout = timeout_func(*args, **kwargs)
46 retries = retries_func(*args, **kwargs)
47 if pass_values:
48 kwargs['timeout'] = timeout
49 kwargs['retries'] = retries
50 def impl():
51 return f(*args, **kwargs)
52 try:
53 if isinstance(threading.current_thread(),
54 timeout_retry.TimeoutRetryThread):
55 return impl()
56 else:
57 return timeout_retry.Run(impl, timeout, retries)
58 except old_errors.WaitForResponseTimedOutError as e:
59 raise device_errors.CommandTimeoutError(str(e)), None, (
60 sys.exc_info()[2])
61 except old_errors.DeviceUnresponsiveError as e:
62 raise device_errors.DeviceUnreachableError(str(e)), None, (
63 sys.exc_info()[2])
64 except reraiser_thread.TimeoutError as e:
65 raise device_errors.CommandTimeoutError(str(e)), None, (
66 sys.exc_info()[2])
67 except cmd_helper.TimeoutError as e:
68 raise device_errors.CommandTimeoutError(str(e)), None, (
69 sys.exc_info()[2])
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.
78 Args:
79 f: The function to decorate.
80 Returns:
81 The decorated function.
82 """
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.
93 Args:
94 timeout: The number of seconds to wait for the decorated function to
95 return. Always used.
96 retries: The number of times the decorated function should be retried on
97 failure. Always used.
98 Returns:
99 The actual decorator.
101 def decorator(f):
102 get_timeout = lambda *a, **kw: timeout
103 get_retries = lambda *a, **kw: retries
104 return _TimeoutRetryWrapper(f, get_timeout, get_retries)
105 return decorator
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.
114 Args:
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.
121 Returns:
122 The actual decorator.
124 def decorator(f):
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)
128 return decorator
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.
142 Args:
143 default_timeout_name: The name of the default timeout attribute of the
144 instance.
145 default_retries_name: The name of the default retries attribute of the
146 instance.
147 Returns:
148 The actual decorator.
150 def decorator(f):
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)
156 return decorator