+
+ def attempts(self):
+ """Return the number of results that have been saved.
+
+ This count includes all kinds of results: success, permanent failure,
+ and temporary failure.
+ """
+ return self._attempts
+
+ def attempts_str(self):
+ """Return a human-friendly string counting saved results.
+
+ This method returns '1 attempt' or 'N attempts', where the number
+ in the string is the number of saved results.
+ """
+ if self._attempts == 1:
+ return '1 attempt'
+ else:
+ return '{} attempts'.format(self._attempts)
+
+
+def check_http_response_success(status_code):
+ """Convert a numeric HTTP status code to a loop control flag.
+
+ This method takes a numeric HTTP status code and returns `True` if
+ the code indicates success, `None` if it indicates temporary
+ failure, and `False` otherwise. You can use this as the
+ `success_check` for a `RetryLoop` that queries the Arvados API server.
+ Specifically:
+
+ * Any 2xx result returns `True`.
+
+ * A select few status codes, or any malformed responses, return `None`.
+
+ * Everything else returns `False`. Note that this includes 1xx and
+ 3xx status codes. They don't indicate success, and you can't
+ retry those requests verbatim.
+
+ Arguments:
+
+ * status_code: int --- A numeric HTTP response code
+ """
+ if status_code in _HTTP_SUCCESSES:
+ return True
+ elif status_code in _HTTP_CAN_RETRY:
+ return None
+ elif 100 <= status_code < 600:
+ return False
+ else:
+ return None # Get well soon, server.
+
+def retry_method(orig_func):
+ """Provide a default value for a method's num_retries argument.
+
+ This is a decorator for instance and class methods that accept a
+ `num_retries` keyword argument, with a `None` default. When the method
+ is called without a value for `num_retries`, this decorator will set it
+ from the `num_retries` attribute of the underlying instance or class.
+
+ Arguments:
+
+ * orig_func: Callable --- A class or instance method that accepts a
+ `num_retries` keyword argument
+ """
+ @functools.wraps(orig_func)
+ def num_retries_setter(self, *args, **kwargs):
+ if kwargs.get('num_retries') is None:
+ kwargs['num_retries'] = self.num_retries
+ return orig_func(self, *args, **kwargs)
+ return num_retries_setter