utils.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import six
  2. import os
  3. from contextlib import contextmanager
  4. import base64
  5. import hashlib
  6. try:
  7. import collections.abc as collections_abc # only works on python 3.3+
  8. except ImportError: #pragma: no cover
  9. import collections as collections_abc
  10. BUFF_SIZE = 16384
  11. # #===========================================================================
  12. def to_native_str(value, encoding='utf-8'):
  13. if isinstance(value, str):
  14. return value
  15. if six.PY3 and isinstance(value, six.binary_type): #pragma: no cover
  16. return value.decode(encoding)
  17. elif six.PY2 and isinstance(value, six.text_type): #pragma: no cover
  18. return value.encode(encoding)
  19. else:
  20. return value
  21. # #===========================================================================
  22. @contextmanager
  23. def open_or_default(filename, mod, default_fh):
  24. if filename == '-' or filename == b'-':
  25. yield default_fh
  26. elif filename and isinstance(filename, str):
  27. res = open(filename, mod)
  28. yield res
  29. res.close()
  30. elif filename:
  31. yield filename
  32. else:
  33. yield default_fh
  34. # #===========================================================================
  35. def headers_to_str_headers(headers):
  36. '''
  37. Converts dict or tuple-based headers of bytes or str to
  38. tuple-based headers of str, which is the python norm (pep 3333)
  39. '''
  40. ret = []
  41. if isinstance(headers, collections_abc.Mapping):
  42. h = headers.items()
  43. else:
  44. h = headers
  45. if six.PY2: #pragma: no cover
  46. return h
  47. for tup in h:
  48. k, v = tup
  49. if isinstance(k, six.binary_type):
  50. k = k.decode('iso-8859-1')
  51. if isinstance(v, six.binary_type):
  52. v = v.decode('iso-8859-1')
  53. ret.append((k, v))
  54. return ret
  55. # ============================================================================
  56. class Digester(object):
  57. def __init__(self, type_='sha1'):
  58. self.type_ = type_
  59. self.digester = hashlib.new(type_)
  60. def update(self, buff):
  61. self.digester.update(buff)
  62. def __str__(self):
  63. return self.type_ + ':' + to_native_str(base64.b32encode(self.digester.digest()))
  64. #=============================================================================
  65. sys_open = open
  66. def open(filename, mode='r', **kwargs): #pragma: no cover
  67. """
  68. open() which supports exclusive mode 'x' in python < 3.3
  69. """
  70. if six.PY3 or 'x' not in mode:
  71. return sys_open(filename, mode, **kwargs)
  72. flags = os.O_EXCL | os.O_CREAT | os.O_WRONLY
  73. if 'b' in mode and hasattr(os, 'O_BINARY'):
  74. flags |= os.O_BINARY
  75. fd = os.open(filename, flags)
  76. mode = mode.replace('x', 'w')
  77. return os.fdopen(fd, mode, 0x664)