compat.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. # Copyright 2012-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  2. #
  3. # Modifications made by Cloudera are:
  4. # Copyright (c) 2016 Cloudera, Inc. All rights reserved.
  5. #
  6. # Licensed under the Apache License, Version 2.0 (the "License"). You
  7. # may not use this file except in compliance with the License. A copy of
  8. # the License is located at
  9. #
  10. # http://aws.amazon.com/apache2.0/
  11. #
  12. # or in the "license" file accompanying this file. This file is
  13. # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
  14. # ANY KIND, either express or implied. See the License for the specific
  15. # language governing permissions and limitations under the License.
  16. import copy
  17. import os
  18. import sys
  19. from altuscli.thirdparty import six # noqa
  20. if six.PY3:
  21. from base64 import encodebytes # noqa
  22. from email.utils import formatdate # noqa
  23. from http.client import HTTPResponse # noqa
  24. import locale
  25. from six.moves import http_client
  26. from urllib.parse import urlsplit # noqa
  27. from urllib.parse import urlunsplit # noqa
  28. raw_input = input
  29. class HTTPHeaders(http_client.HTTPMessage):
  30. pass
  31. def get_stdout_text_writer():
  32. return sys.stdout
  33. def ensure_unicode(s, encoding=None, errors=None):
  34. # NOOP in Python 3, because every string is already unicode
  35. return s
  36. def compat_open(filename, mode='r', encoding=None):
  37. """Back-port open() that accepts an encoding argument.
  38. In python3 this uses the built in open() and in python2 this
  39. uses the io.open() function.
  40. If the file is not being opened in binary mode, then we'll
  41. use locale.getpreferredencoding() to find the preferred
  42. encoding.
  43. """
  44. if 'b' not in mode:
  45. encoding = locale.getpreferredencoding()
  46. return open(filename, mode, encoding=encoding)
  47. else:
  48. from base64 import encodestring as encodebytes # noqa
  49. import codecs
  50. from email.message import Message
  51. from email.Utils import formatdate # noqa
  52. from httplib import HTTPResponse # noqa
  53. import io
  54. import locale
  55. from urlparse import urlsplit # noqa
  56. from urlparse import urlunsplit # noqa
  57. raw_input = raw_input
  58. class HTTPHeaders(Message):
  59. # The __iter__ method is not available in python2.x, so we have
  60. # to port the py3 version.
  61. def __iter__(self):
  62. for field, value in self._headers:
  63. yield field
  64. def get_stdout_text_writer():
  65. # In python3, all the sys.stdout/sys.stderr streams are in text
  66. # mode. This means they expect unicode, and will encode the
  67. # unicode automatically before actually writing to stdout/stderr.
  68. # In python2, that's not the case. In order to provide a consistent
  69. # interface, we can create a wrapper around sys.stdout that will take
  70. # unicode, and automatically encode it to the preferred encoding.
  71. # That way consumers can just call get_stdout_text_writer() and write
  72. # unicode to the returned stream. Note that get_stdout_text_writer
  73. # just returns sys.stdout in the PY3 section above because python3
  74. # handles this.
  75. return codecs.getwriter(locale.getpreferredencoding())(sys.stdout)
  76. def ensure_unicode(s, encoding='utf-8', errors='strict'):
  77. if isinstance(s, six.text_type):
  78. return s
  79. return unicode(s, encoding, errors)
  80. def compat_open(filename, mode='r', encoding=None):
  81. # See docstring for compat_open in the PY3 section above.
  82. if 'b' not in mode:
  83. encoding = locale.getpreferredencoding()
  84. return io.open(filename, mode, encoding=encoding)
  85. try:
  86. from collections import OrderedDict
  87. except ImportError:
  88. from ordereddict import OrderedDict # noqa
  89. if sys.version_info[:2] == (2, 6):
  90. import simplejson as json
  91. else:
  92. import json # noqa
  93. @classmethod
  94. def from_dict(cls, d):
  95. new_instance = cls()
  96. for key, value in d.items():
  97. new_instance[key] = value
  98. return new_instance
  99. @classmethod
  100. def from_pairs(cls, pairs):
  101. new_instance = cls()
  102. for key, value in pairs:
  103. new_instance[key] = value
  104. return new_instance
  105. HTTPHeaders.from_dict = from_dict
  106. HTTPHeaders.from_pairs = from_pairs
  107. def copy_kwargs(kwargs):
  108. """
  109. There is a bug in Python versions < 2.6.5 that prevents you from passing
  110. unicode keyword args (#4978). This function takes a dictionary of kwargs and
  111. returns a copy. If you are using Python < 2.6.5, it also encodes the keys to
  112. avoid this bug. Oh, and version_info wasn't a namedtuple back then, either!
  113. """
  114. vi = sys.version_info
  115. if vi[0] == 2 and vi[1] <= 6 and vi[3] < 5:
  116. copy_kwargs = {}
  117. for key in kwargs:
  118. copy_kwargs[key.encode('utf-8')] = kwargs[key]
  119. else:
  120. copy_kwargs = copy.copy(kwargs)
  121. return copy_kwargs
  122. def compat_input(prompt, interactive_long_input=False):
  123. """
  124. Cygwin's pty's are based on pipes. Therefore, when it interacts with a Win32
  125. program (such as Win32 python), what that program sees is a pipe instead of
  126. a console. This is important because python buffers pipes, and so on a
  127. pty-based terminal, text will not necessarily appear immediately. In most
  128. cases, this isn't a big deal. But when we're doing an interactive prompt,
  129. the result is that the prompts won't display until we fill the buffer. Since
  130. raw_input does not flush the prompt, we need to manually write and flush it.
  131. See https://github.com/mintty/mintty/issues/56 for more details.
  132. """
  133. is_windows = sys.platform.startswith('win')
  134. if interactive_long_input:
  135. # See THUN-222 for context on why this is necessary
  136. if is_windows is False:
  137. os.system('stty -icanon')
  138. sys.stdout.write(prompt)
  139. sys.stdout.flush()
  140. if is_windows is False:
  141. os.system('stty sane')
  142. return raw_input()