compat.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. # coding=utf-8
  2. #
  3. # This file is part of Hypothesis, which may be found at
  4. # https://github.com/HypothesisWorks/hypothesis-python
  5. #
  6. # Most of this work is copyright (C) 2013-2018 David R. MacIver
  7. # (david@drmaciver.com), but it contains contributions by others. See
  8. # CONTRIBUTING.rst for a full list of people who may hold copyright, and
  9. # consult the git log if you need to determine who owns an individual
  10. # contribution.
  11. #
  12. # This Source Code Form is subject to the terms of the Mozilla Public License,
  13. # v. 2.0. If a copy of the MPL was not distributed with this file, You can
  14. # obtain one at http://mozilla.org/MPL/2.0/.
  15. #
  16. # END HEADER
  17. # pylint: skip-file
  18. from __future__ import division, print_function, absolute_import
  19. import re
  20. import sys
  21. import math
  22. import time
  23. import codecs
  24. import platform
  25. import importlib
  26. from base64 import b64encode
  27. from collections import namedtuple
  28. try:
  29. from collections import OrderedDict, Counter
  30. except ImportError: # pragma: no cover
  31. from ordereddict import OrderedDict
  32. from counter import Counter
  33. PY2 = sys.version_info[0] == 2
  34. PY3 = sys.version_info[0] == 3
  35. PYPY = platform.python_implementation() == 'PyPy'
  36. CAN_UNPACK_BYTE_ARRAY = sys.version_info[:3] >= (2, 7, 4)
  37. WINDOWS = platform.system() == 'Windows'
  38. if sys.version_info[:2] <= (2, 6):
  39. raise ImportError(
  40. 'Hypothesis is not supported on Python versions before 2.7'
  41. )
  42. def bit_length(n):
  43. return n.bit_length()
  44. if PY3:
  45. def str_to_bytes(s):
  46. return s.encode(a_good_encoding())
  47. def int_to_text(i):
  48. return str(i)
  49. text_type = str
  50. binary_type = bytes
  51. hrange = range
  52. ARG_NAME_ATTRIBUTE = 'arg'
  53. integer_types = (int,)
  54. hunichr = chr
  55. def unicode_safe_repr(x):
  56. return repr(x)
  57. def isidentifier(s):
  58. return s.isidentifier()
  59. def escape_unicode_characters(s):
  60. return codecs.encode(s, 'unicode_escape').decode('ascii')
  61. def print_unicode(x):
  62. print(x)
  63. exec("""
  64. def quiet_raise(exc):
  65. raise exc from None
  66. """)
  67. def int_from_bytes(data):
  68. return int.from_bytes(data, 'big')
  69. def int_to_bytes(i, size):
  70. return i.to_bytes(size, 'big')
  71. def to_bytes_sequence(ls):
  72. return bytes(ls)
  73. def int_to_byte(i):
  74. return bytes([i])
  75. import struct
  76. struct_pack = struct.pack
  77. struct_unpack = struct.unpack
  78. def benchmark_time():
  79. return time.monotonic()
  80. else:
  81. import struct
  82. def struct_pack(*args):
  83. return hbytes(struct.pack(*args))
  84. if CAN_UNPACK_BYTE_ARRAY:
  85. def struct_unpack(fmt, string):
  86. return struct.unpack(fmt, string)
  87. else:
  88. def struct_unpack(fmt, string):
  89. return struct.unpack(fmt, str(string))
  90. def int_from_bytes(data):
  91. assert isinstance(data, bytearray)
  92. if CAN_UNPACK_BYTE_ARRAY:
  93. unpackable_data = data
  94. else:
  95. unpackable_data = bytes(data)
  96. result = 0
  97. i = 0
  98. while i + 4 <= len(data):
  99. result <<= 32
  100. result |= struct.unpack('>I', unpackable_data[i:i + 4])[0]
  101. i += 4
  102. while i < len(data):
  103. result <<= 8
  104. result |= data[i]
  105. i += 1
  106. return int(result)
  107. def int_to_bytes(i, size):
  108. assert i >= 0
  109. result = bytearray(size)
  110. j = size - 1
  111. while i and j >= 0:
  112. result[j] = i & 255
  113. i >>= 8
  114. j -= 1
  115. if i:
  116. raise OverflowError('int too big to convert')
  117. return hbytes(result)
  118. int_to_byte = chr
  119. def to_bytes_sequence(ls):
  120. return bytearray(ls)
  121. def str_to_bytes(s):
  122. return s
  123. def int_to_text(i):
  124. return str(i).decode('ascii')
  125. VALID_PYTHON_IDENTIFIER = re.compile(
  126. r"^[a-zA-Z_][a-zA-Z0-9_]*$"
  127. )
  128. def isidentifier(s):
  129. return VALID_PYTHON_IDENTIFIER.match(s)
  130. def unicode_safe_repr(x):
  131. r = repr(x)
  132. assert isinstance(r, str)
  133. return r.decode(a_good_encoding())
  134. text_type = unicode
  135. binary_type = str
  136. def hrange(start_or_finish, finish=None, step=None):
  137. try:
  138. if step is None:
  139. if finish is None:
  140. return xrange(start_or_finish)
  141. else:
  142. return xrange(start_or_finish, finish)
  143. else:
  144. return xrange(start_or_finish, finish, step)
  145. except OverflowError:
  146. if step == 0:
  147. raise ValueError(u'step argument may not be zero')
  148. if step is None:
  149. step = 1
  150. if finish is not None:
  151. start = start_or_finish
  152. else:
  153. start = 0
  154. finish = start_or_finish
  155. assert step != 0
  156. if step > 0:
  157. def shimrange():
  158. i = start
  159. while i < finish:
  160. yield i
  161. i += step
  162. else:
  163. def shimrange():
  164. i = start
  165. while i > finish:
  166. yield i
  167. i += step
  168. return shimrange()
  169. ARG_NAME_ATTRIBUTE = 'id'
  170. integer_types = (int, long)
  171. hunichr = unichr
  172. def escape_unicode_characters(s):
  173. return codecs.encode(s, 'string_escape')
  174. def print_unicode(x):
  175. if isinstance(x, unicode):
  176. x = x.encode(a_good_encoding())
  177. print(x)
  178. def quiet_raise(exc):
  179. raise exc
  180. def benchmark_time():
  181. return time.time()
  182. # coverage mixes unicode and str filepaths on Python 2, which causes us
  183. # problems if we're running under unicodenazi (it might also cause problems
  184. # when not running under unicodenazi, but hard to say for sure). This method
  185. # exists to work around that: If we're given a unicode filepath, we turn it
  186. # into a string file path using the appropriate encoding. See
  187. # https://bitbucket.org/ned/coveragepy/issues/602/ for more information.
  188. if PY2:
  189. def encoded_filepath(filepath):
  190. if isinstance(filepath, text_type):
  191. return filepath.encode(sys.getfilesystemencoding())
  192. else:
  193. return filepath
  194. else:
  195. def encoded_filepath(filepath):
  196. return filepath
  197. def a_good_encoding():
  198. return 'utf-8'
  199. def to_unicode(x):
  200. if isinstance(x, text_type):
  201. return x
  202. else:
  203. return x.decode(a_good_encoding())
  204. def qualname(f):
  205. try:
  206. return f.__qualname__
  207. except AttributeError:
  208. pass
  209. try:
  210. return f.im_class.__name__ + '.' + f.__name__
  211. except AttributeError:
  212. return f.__name__
  213. if PY2:
  214. FullArgSpec = namedtuple('FullArgSpec', 'args, varargs, varkw, defaults, '
  215. 'kwonlyargs, kwonlydefaults, annotations')
  216. def getfullargspec(func):
  217. import inspect
  218. args, varargs, varkw, defaults = inspect.getargspec(func)
  219. return FullArgSpec(args, varargs, varkw, defaults, [], None,
  220. getattr(func, '__annotations__', {}))
  221. else:
  222. from inspect import getfullargspec, FullArgSpec
  223. if sys.version_info[:2] < (3, 6):
  224. def get_type_hints(thing):
  225. try:
  226. spec = getfullargspec(thing)
  227. return {
  228. k: v for k, v in spec.annotations.items()
  229. if k in (spec.args + spec.kwonlyargs) and isinstance(v, type)
  230. }
  231. except TypeError:
  232. return {}
  233. else:
  234. def get_type_hints(thing):
  235. try:
  236. import typing
  237. return typing.get_type_hints(thing)
  238. except TypeError:
  239. return {}
  240. importlib_invalidate_caches = getattr(
  241. importlib, 'invalidate_caches', lambda: ())
  242. if PY2:
  243. CODE_FIELD_ORDER = [
  244. 'co_argcount',
  245. 'co_nlocals',
  246. 'co_stacksize',
  247. 'co_flags',
  248. 'co_code',
  249. 'co_consts',
  250. 'co_names',
  251. 'co_varnames',
  252. 'co_filename',
  253. 'co_name',
  254. 'co_firstlineno',
  255. 'co_lnotab',
  256. 'co_freevars',
  257. 'co_cellvars',
  258. ]
  259. else:
  260. CODE_FIELD_ORDER = [
  261. 'co_argcount',
  262. 'co_kwonlyargcount',
  263. 'co_nlocals',
  264. 'co_stacksize',
  265. 'co_flags',
  266. 'co_code',
  267. 'co_consts',
  268. 'co_names',
  269. 'co_varnames',
  270. 'co_filename',
  271. 'co_name',
  272. 'co_firstlineno',
  273. 'co_lnotab',
  274. 'co_freevars',
  275. 'co_cellvars',
  276. ]
  277. def update_code_location(code, newfile, newlineno):
  278. """Take a code object and lie shamelessly about where it comes from.
  279. Why do we want to do this? It's for really shallow reasons involving
  280. hiding the hypothesis_temporary_module code from test runners like
  281. py.test's verbose mode. This is a vastly disproportionate terrible
  282. hack that I've done purely for vanity, and if you're reading this
  283. code you're probably here because it's broken something and now
  284. you're angry at me. Sorry.
  285. """
  286. unpacked = [
  287. getattr(code, name) for name in CODE_FIELD_ORDER
  288. ]
  289. unpacked[CODE_FIELD_ORDER.index('co_filename')] = newfile
  290. unpacked[CODE_FIELD_ORDER.index('co_firstlineno')] = newlineno
  291. return type(code)(*unpacked)
  292. class compatbytes(bytearray):
  293. __name__ = 'bytes'
  294. def __init__(self, *args, **kwargs):
  295. bytearray.__init__(self, *args, **kwargs)
  296. self.__hash = None
  297. def __str__(self):
  298. return bytearray.__str__(self)
  299. def __repr__(self):
  300. return 'compatbytes(b%r)' % (str(self),)
  301. def __hash__(self):
  302. if self.__hash is None:
  303. self.__hash = hash(str(self))
  304. return self.__hash
  305. def count(self, value):
  306. c = 0
  307. for w in self:
  308. if w == value:
  309. c += 1
  310. return c
  311. def index(self, value):
  312. for i, v in enumerate(self):
  313. if v == value:
  314. return i
  315. raise ValueError('Value %r not in sequence %r' % (value, self))
  316. def __add__(self, value):
  317. assert isinstance(value, compatbytes)
  318. return compatbytes(bytearray.__add__(self, value))
  319. def __radd__(self, value):
  320. assert isinstance(value, compatbytes)
  321. return compatbytes(bytearray.__add__(value, self))
  322. def __mul__(self, value):
  323. return compatbytes(bytearray.__mul__(self, value))
  324. def __rmul__(self, value):
  325. return compatbytes(bytearray.__rmul__(self, value))
  326. def __getitem__(self, *args, **kwargs):
  327. r = bytearray.__getitem__(self, *args, **kwargs)
  328. if isinstance(r, bytearray):
  329. return compatbytes(r)
  330. else:
  331. return r
  332. __setitem__ = None
  333. def join(self, parts):
  334. result = bytearray()
  335. first = True
  336. for p in parts:
  337. if not first:
  338. result.extend(self)
  339. first = False
  340. result.extend(p)
  341. return compatbytes(result)
  342. def __contains__(self, value):
  343. return any(v == value for v in self)
  344. if PY2:
  345. hbytes = compatbytes
  346. reasonable_byte_type = bytearray
  347. string_types = (str, unicode)
  348. else:
  349. hbytes = bytes
  350. reasonable_byte_type = bytes
  351. string_types = (str,)
  352. EMPTY_BYTES = hbytes(b'')
  353. if PY2:
  354. def to_str(s):
  355. if isinstance(s, unicode):
  356. return s.encode(a_good_encoding())
  357. assert isinstance(s, str)
  358. return s
  359. else:
  360. def to_str(s):
  361. return s
  362. def cast_unicode(s, encoding=None):
  363. if isinstance(s, bytes):
  364. return s.decode(encoding or a_good_encoding(), 'replace')
  365. return s
  366. def get_stream_enc(stream, default=None):
  367. return getattr(stream, 'encoding', None) or default
  368. def implements_iterator(it):
  369. """Turn things with a __next__ attribute into iterators on Python 2."""
  370. if PY2 and not hasattr(it, 'next') and hasattr(it, '__next__'):
  371. it.next = it.__next__
  372. return it
  373. if PY3:
  374. FileNotFoundError = FileNotFoundError
  375. else:
  376. FileNotFoundError = IOError
  377. # We need to know what sort of exception gets thrown when you try to write over
  378. # an existing file where you're not allowed to. This is rather less consistent
  379. # between versions than might be hoped.
  380. if PY3:
  381. FileExistsError = FileExistsError
  382. elif WINDOWS:
  383. FileExistsError = WindowsError
  384. else:
  385. # This doesn't happen in this case: We're not on windows and don't support
  386. # the x flag because it's Python 2, so there are no places where this can
  387. # be thrown.
  388. FileExistsError = None
  389. if PY2:
  390. # Under Python 2, math.floor and math.ceil return floats, which cannot
  391. # represent large integers - eg `float(2**53) == float(2**53 + 1)`.
  392. # We therefore implement them entirely in (long) integer operations.
  393. def floor(x):
  394. if int(x) != x and x < 0:
  395. return int(x) - 1
  396. return int(x)
  397. def ceil(x):
  398. if int(x) != x and x > 0:
  399. return int(x) + 1
  400. return int(x)
  401. else:
  402. floor = math.floor
  403. ceil = math.ceil
  404. try:
  405. from math import gcd
  406. except ImportError:
  407. from fractions import gcd
  408. if PY2:
  409. def b64decode(s):
  410. from base64 import b64decode as base
  411. return hbytes(base(s))
  412. else:
  413. from base64 import b64decode