lib.py 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. import sys
  2. import locale
  3. def to_utf8(s):
  4. """Re-encode string from the default system encoding to UTF-8."""
  5. current = locale.getpreferredencoding()
  6. return s.decode(current).encode("UTF-8") if s and current != "UTF-8" else s
  7. def debug(obj, fd=sys.stderr):
  8. """Write obj to standard error."""
  9. string = str(obj.encode(get_encoding(fd), "backslashreplace")
  10. if isinstance(obj, unicode) else obj)
  11. fd.write(string + "\n")
  12. def catch_exceptions(exit_codes, fun, *args, **kwargs):
  13. """
  14. Catch exceptions on fun(*args, **kwargs) and return the exit code specified
  15. in the exit_codes dictionary. Return 0 if no exception is raised.
  16. """
  17. try:
  18. fun(*args, **kwargs)
  19. return 0
  20. except tuple(exit_codes.keys()) as exc:
  21. debug("[%s] %s" % (exc.__class__.__name__, exc))
  22. return exit_codes[exc.__class__]
  23. def get_encoding(fd):
  24. """Guess terminal encoding."""
  25. return fd.encoding or locale.getpreferredencoding()
  26. def first(it):
  27. """Return first element in iterable."""
  28. return it.next()
  29. def string_to_dict(string):
  30. """Return dictionary from string "key1=value1, key2=value2"."""
  31. pairs = [s.strip() for s in (string or "").split(",")]
  32. return dict(pair.split("=") for pair in pairs)
  33. def retriable_exceptions(fun, retriable_exceptions, max_retries=None):
  34. """Run function and retry on some exceptions (with exponential backoff)."""
  35. retry = 0
  36. while 1:
  37. try:
  38. return fun()
  39. except tuple(retriable_exceptions) as exc:
  40. retry += 1
  41. if type(exc) not in retriable_exceptions:
  42. raise exc
  43. elif max_retries is not None and retry > max_retries:
  44. lib.debug("Retry limit reached, time to give up")
  45. raise exc
  46. else:
  47. seconds = random.uniform(0, 2**retry)
  48. lib.debug("Retryable error {}/{}: {}. Waiting {} seconds".
  49. format(retry, max_retries or "-", type(exc).__name__, seconds))
  50. time.sleep(seconds)