lib.py 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  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. if string:
  32. pairs = [s.strip() for s in string.split(",")]
  33. return dict(pair.split("=") for pair in pairs)
  34. def retriable_exceptions(fun, retriable_exceptions, max_retries=None):
  35. """Run function and retry on some exceptions (with exponential backoff)."""
  36. retry = 0
  37. while 1:
  38. try:
  39. return fun()
  40. except tuple(retriable_exceptions) as exc:
  41. retry += 1
  42. if type(exc) not in retriable_exceptions:
  43. raise exc
  44. elif max_retries is not None and retry > max_retries:
  45. lib.debug("Retry limit reached, time to give up")
  46. raise exc
  47. else:
  48. seconds = random.uniform(0, 2**retry)
  49. lib.debug("Retryable error {0}/{1}: {2}. Waiting {3} seconds".
  50. format(retry, max_retries or "-", type(exc).__name__, seconds))
  51. time.sleep(seconds)