validation.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  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 math
  19. from numbers import Rational
  20. from hypothesis.errors import InvalidArgument
  21. from hypothesis.internal.compat import integer_types
  22. from hypothesis.internal.coverage import check_function
  23. @check_function
  24. def check_type(typ, arg, name=''):
  25. if name:
  26. name += '='
  27. if not isinstance(arg, typ):
  28. if isinstance(typ, type):
  29. typ_string = typ.__name__
  30. else:
  31. typ_string = 'one of %s' % (
  32. ', '.join(t.__name__ for t in typ))
  33. raise InvalidArgument('Expected %s but got %s%r (type=%s)'
  34. % (typ_string, name, arg, type(arg).__name__))
  35. @check_function
  36. def check_strategy(arg, name=''):
  37. from hypothesis.searchstrategy import SearchStrategy
  38. check_type(SearchStrategy, arg, name)
  39. @check_function
  40. def check_valid_integer(value):
  41. """Checks that value is either unspecified, or a valid integer.
  42. Otherwise raises InvalidArgument.
  43. """
  44. if value is None:
  45. return
  46. check_type(integer_types, value)
  47. @check_function
  48. def check_valid_bound(value, name):
  49. """Checks that value is either unspecified, or a valid interval bound.
  50. Otherwise raises InvalidArgument.
  51. """
  52. if value is None or isinstance(value, integer_types + (Rational,)):
  53. return
  54. if math.isnan(value):
  55. raise InvalidArgument(u'Invalid end point %s=%r' % (name, value))
  56. @check_function
  57. def try_convert(typ, value, name):
  58. if value is None:
  59. return None
  60. if isinstance(value, typ):
  61. return value
  62. try:
  63. return typ(value)
  64. except TypeError:
  65. raise InvalidArgument(
  66. 'Cannot convert %s=%r of type %s to type %s' % (
  67. name, value, type(value).__name__, typ.__name__
  68. )
  69. )
  70. except (OverflowError, ValueError):
  71. raise InvalidArgument(
  72. 'Cannot convert %s=%r to type %s' % (
  73. name, value, typ.__name__
  74. )
  75. )
  76. @check_function
  77. def check_valid_size(value, name):
  78. """Checks that value is either unspecified, or a valid non-negative size
  79. expressed as an integer/float.
  80. Otherwise raises InvalidArgument.
  81. """
  82. if value is None:
  83. return
  84. check_type(integer_types + (float,), value)
  85. if value < 0:
  86. raise InvalidArgument(u'Invalid size %s=%r < 0' % (name, value))
  87. if isinstance(value, float) and math.isnan(value):
  88. raise InvalidArgument(u'Invalid size %s=%r' % (name, value))
  89. @check_function
  90. def check_valid_interval(lower_bound, upper_bound, lower_name, upper_name):
  91. """Checks that lower_bound and upper_bound are either unspecified, or they
  92. define a valid interval on the number line.
  93. Otherwise raises InvalidArgument.
  94. """
  95. if lower_bound is None or upper_bound is None:
  96. return
  97. if upper_bound < lower_bound:
  98. raise InvalidArgument(
  99. 'Cannot have %s=%r < %s=%r' % (
  100. upper_name, upper_bound, lower_name, lower_bound
  101. ))
  102. @check_function
  103. def check_valid_sizes(min_size, average_size, max_size):
  104. check_valid_size(min_size, 'min_size')
  105. check_valid_size(max_size, 'max_size')
  106. check_valid_size(average_size, 'average_size')
  107. check_valid_interval(min_size, max_size, 'min_size', 'max_size')
  108. check_valid_interval(average_size, max_size, 'average_size', 'max_size')
  109. check_valid_interval(min_size, average_size, 'min_size', 'average_size')
  110. if (
  111. average_size == 0 and (
  112. max_size is None or
  113. max_size > 0
  114. )
  115. ):
  116. raise InvalidArgument(
  117. 'Cannot have average_size=%r with non-zero max_size=%r' % (
  118. average_size, min_size
  119. ))