escalation.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  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. from __future__ import division, print_function, absolute_import
  18. import os
  19. import sys
  20. import coverage
  21. import hypothesis
  22. from hypothesis.errors import StopTest, DeadlineExceeded, \
  23. HypothesisException, UnsatisfiedAssumption
  24. from hypothesis.internal.compat import text_type, binary_type, \
  25. encoded_filepath
  26. def belongs_to(package):
  27. root = os.path.dirname(package.__file__)
  28. cache = {text_type: {}, binary_type: {}}
  29. def accept(filepath):
  30. ftype = type(filepath)
  31. try:
  32. return cache[ftype][filepath]
  33. except KeyError:
  34. pass
  35. new_filepath = encoded_filepath(filepath)
  36. result = os.path.abspath(new_filepath).startswith(root)
  37. cache[ftype][filepath] = result
  38. cache[type(new_filepath)][new_filepath] = result
  39. return result
  40. accept.__name__ = 'is_%s_file' % (package.__name__,)
  41. return accept
  42. PREVENT_ESCALATION = os.getenv('HYPOTHESIS_DO_NOT_ESCALATE') == 'true'
  43. FILE_CACHE = {}
  44. is_hypothesis_file = belongs_to(hypothesis)
  45. is_coverage_file = belongs_to(coverage)
  46. HYPOTHESIS_CONTROL_EXCEPTIONS = (
  47. DeadlineExceeded, StopTest, UnsatisfiedAssumption
  48. )
  49. def mark_for_escalation(e):
  50. if not isinstance(e, HYPOTHESIS_CONTROL_EXCEPTIONS):
  51. e.hypothesis_internal_always_escalate = True
  52. def escalate_hypothesis_internal_error():
  53. if PREVENT_ESCALATION:
  54. return
  55. error_type, e, tb = sys.exc_info()
  56. if getattr(e, 'hypothesis_internal_always_escalate', False):
  57. raise
  58. import traceback
  59. filepath = traceback.extract_tb(tb)[-1][0]
  60. if is_hypothesis_file(filepath) and not isinstance(
  61. e, (HypothesisException,) + HYPOTHESIS_CONTROL_EXCEPTIONS,
  62. ):
  63. raise
  64. # This is so that if we do something wrong and trigger an internal Coverage
  65. # error we don't try to catch it. It should be impossible to trigger, but
  66. # you never know.
  67. if is_coverage_file(filepath): # pragma: no cover
  68. raise