compat.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. # coding: utf-8
  2. from __future__ import print_function
  3. # partially from package six by Benjamin Peterson
  4. import sys
  5. import os
  6. import types
  7. import traceback
  8. from abc import abstractmethod
  9. # fmt: off
  10. if False: # MYPY
  11. from typing import Any, Dict, Optional, List, Union, BinaryIO, IO, Text, Tuple # NOQA
  12. from typing import Optional # NOQA
  13. # fmt: on
  14. _DEFAULT_YAML_VERSION = (1, 2)
  15. try:
  16. from ruamel.ordereddict import ordereddict
  17. except: # NOQA
  18. try:
  19. from collections import OrderedDict
  20. except ImportError:
  21. from ordereddict import OrderedDict # type: ignore
  22. # to get the right name import ... as ordereddict doesn't do that
  23. class ordereddict(OrderedDict): # type: ignore
  24. if not hasattr(OrderedDict, 'insert'):
  25. def insert(self, pos, key, value):
  26. # type: (int, Any, Any) -> None
  27. if pos >= len(self):
  28. self[key] = value
  29. return
  30. od = ordereddict()
  31. od.update(self)
  32. for k in od:
  33. del self[k]
  34. for index, old_key in enumerate(od):
  35. if pos == index:
  36. self[key] = value
  37. self[old_key] = od[old_key]
  38. PY2 = sys.version_info[0] == 2
  39. PY3 = sys.version_info[0] == 3
  40. if PY3:
  41. def utf8(s):
  42. # type: (str) -> str
  43. return s
  44. def to_str(s):
  45. # type: (str) -> str
  46. return s
  47. def to_unicode(s):
  48. # type: (str) -> str
  49. return s
  50. else:
  51. if False:
  52. unicode = str
  53. def utf8(s):
  54. # type: (unicode) -> str
  55. return s.encode('utf-8')
  56. def to_str(s):
  57. # type: (str) -> str
  58. return str(s)
  59. def to_unicode(s):
  60. # type: (str) -> unicode
  61. return unicode(s) # NOQA
  62. if PY3:
  63. string_types = str
  64. integer_types = int
  65. class_types = type
  66. text_type = str
  67. binary_type = bytes
  68. MAXSIZE = sys.maxsize
  69. unichr = chr
  70. import io
  71. StringIO = io.StringIO
  72. BytesIO = io.BytesIO
  73. # have unlimited precision
  74. no_limit_int = int
  75. from collections.abc import Hashable, MutableSequence, MutableMapping, Mapping # NOQA
  76. else:
  77. string_types = basestring # NOQA
  78. integer_types = (int, long) # NOQA
  79. class_types = (type, types.ClassType)
  80. text_type = unicode # NOQA
  81. binary_type = str
  82. # to allow importing
  83. unichr = unichr
  84. from StringIO import StringIO as _StringIO
  85. StringIO = _StringIO
  86. import cStringIO
  87. BytesIO = cStringIO.StringIO
  88. # have unlimited precision
  89. no_limit_int = long # NOQA not available on Python 3
  90. from collections import Hashable, MutableSequence, MutableMapping, Mapping # NOQA
  91. if False: # MYPY
  92. # StreamType = Union[BinaryIO, IO[str], IO[unicode], StringIO]
  93. # StreamType = Union[BinaryIO, IO[str], StringIO] # type: ignore
  94. StreamType = Any
  95. StreamTextType = StreamType # Union[Text, StreamType]
  96. VersionType = Union[List[int], str, Tuple[int, int]]
  97. if PY3:
  98. builtins_module = 'builtins'
  99. else:
  100. builtins_module = '__builtin__'
  101. UNICODE_SIZE = 4 if sys.maxunicode > 65535 else 2
  102. def with_metaclass(meta, *bases):
  103. # type: (Any, Any) -> Any
  104. """Create a base class with a metaclass."""
  105. return meta('NewBase', bases, {})
  106. DBG_TOKEN = 1
  107. DBG_EVENT = 2
  108. DBG_NODE = 4
  109. _debug = None # type: Optional[int]
  110. if 'RUAMELDEBUG' in os.environ:
  111. _debugx = os.environ.get('RUAMELDEBUG')
  112. if _debugx is None:
  113. _debug = 0
  114. else:
  115. _debug = int(_debugx)
  116. if bool(_debug):
  117. class ObjectCounter(object):
  118. def __init__(self):
  119. # type: () -> None
  120. self.map = {} # type: Dict[Any, Any]
  121. def __call__(self, k):
  122. # type: (Any) -> None
  123. self.map[k] = self.map.get(k, 0) + 1
  124. def dump(self):
  125. # type: () -> None
  126. for k in sorted(self.map):
  127. sys.stdout.write('{} -> {}'.format(k, self.map[k]))
  128. object_counter = ObjectCounter()
  129. # used from yaml util when testing
  130. def dbg(val=None):
  131. # type: (Any) -> Any
  132. global _debug
  133. if _debug is None:
  134. # set to true or false
  135. _debugx = os.environ.get('YAMLDEBUG')
  136. if _debugx is None:
  137. _debug = 0
  138. else:
  139. _debug = int(_debugx)
  140. if val is None:
  141. return _debug
  142. return _debug & val
  143. class Nprint(object):
  144. def __init__(self, file_name=None):
  145. # type: (Any) -> None
  146. self._max_print = None # type: Any
  147. self._count = None # type: Any
  148. self._file_name = file_name
  149. def __call__(self, *args, **kw):
  150. # type: (Any, Any) -> None
  151. if not bool(_debug):
  152. return
  153. out = sys.stdout if self._file_name is None else open(self._file_name, 'a')
  154. dbgprint = print # to fool checking for print statements by dv utility
  155. kw1 = kw.copy()
  156. kw1['file'] = out
  157. dbgprint(*args, **kw1)
  158. out.flush()
  159. if self._max_print is not None:
  160. if self._count is None:
  161. self._count = self._max_print
  162. self._count -= 1
  163. if self._count == 0:
  164. dbgprint('forced exit\n')
  165. traceback.print_stack()
  166. out.flush()
  167. sys.exit(0)
  168. if self._file_name:
  169. out.close()
  170. def set_max_print(self, i):
  171. # type: (int) -> None
  172. self._max_print = i
  173. self._count = None
  174. nprint = Nprint()
  175. nprintf = Nprint('/var/tmp/ruamel.yaml.log')
  176. # char checkers following production rules
  177. def check_namespace_char(ch):
  178. # type: (Any) -> bool
  179. if u'\x21' <= ch <= u'\x7E': # ! to ~
  180. return True
  181. if u'\xA0' <= ch <= u'\uD7FF':
  182. return True
  183. if (u'\uE000' <= ch <= u'\uFFFD') and ch != u'\uFEFF': # excl. byte order mark
  184. return True
  185. if u'\U00010000' <= ch <= u'\U0010FFFF':
  186. return True
  187. return False
  188. def check_anchorname_char(ch):
  189. # type: (Any) -> bool
  190. if ch in u',[]{}':
  191. return False
  192. return check_namespace_char(ch)
  193. def version_tnf(t1, t2=None):
  194. # type: (Any, Any) -> Any
  195. """
  196. return True if ruamel.yaml version_info < t1, None if t2 is specified and bigger else False
  197. """
  198. from ruamel.yaml import version_info # NOQA
  199. if version_info < t1:
  200. return True
  201. if t2 is not None and version_info < t2:
  202. return None
  203. return False
  204. class MutableSliceableSequence(MutableSequence): # type: ignore
  205. __slots__ = ()
  206. def __getitem__(self, index):
  207. # type: (Any) -> Any
  208. if not isinstance(index, slice):
  209. return self.__getsingleitem__(index)
  210. return type(self)([self[i] for i in range(*index.indices(len(self)))]) # type: ignore
  211. def __setitem__(self, index, value):
  212. # type: (Any, Any) -> None
  213. if not isinstance(index, slice):
  214. return self.__setsingleitem__(index, value)
  215. assert iter(value)
  216. # nprint(index.start, index.stop, index.step, index.indices(len(self)))
  217. if index.step is None:
  218. del self[index.start : index.stop]
  219. for elem in reversed(value):
  220. self.insert(0 if index.start is None else index.start, elem)
  221. else:
  222. range_parms = index.indices(len(self))
  223. nr_assigned_items = (range_parms[1] - range_parms[0] - 1) // range_parms[2] + 1
  224. # need to test before changing, in case TypeError is caught
  225. if nr_assigned_items < len(value):
  226. raise TypeError(
  227. 'too many elements in value {} < {}'.format(nr_assigned_items, len(value))
  228. )
  229. elif nr_assigned_items > len(value):
  230. raise TypeError(
  231. 'not enough elements in value {} > {}'.format(
  232. nr_assigned_items, len(value)
  233. )
  234. )
  235. for idx, i in enumerate(range(*range_parms)):
  236. self[i] = value[idx]
  237. def __delitem__(self, index):
  238. # type: (Any) -> None
  239. if not isinstance(index, slice):
  240. return self.__delsingleitem__(index)
  241. # nprint(index.start, index.stop, index.step, index.indices(len(self)))
  242. for i in reversed(range(*index.indices(len(self)))):
  243. del self[i]
  244. @abstractmethod
  245. def __getsingleitem__(self, index):
  246. # type: (Any) -> Any
  247. raise IndexError
  248. @abstractmethod
  249. def __setsingleitem__(self, index, value):
  250. # type: (Any, Any) -> None
  251. raise IndexError
  252. @abstractmethod
  253. def __delsingleitem__(self, index):
  254. # type: (Any) -> None
  255. raise IndexError