iscloseto.py 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. import six
  2. from hamcrest.core.base_matcher import BaseMatcher
  3. from math import fabs
  4. __author__ = "Jon Reid"
  5. __copyright__ = "Copyright 2011 hamcrest.org"
  6. __license__ = "BSD, see License.txt"
  7. def isnumeric(value):
  8. """Confirm that 'value' can be treated numerically; duck-test accordingly
  9. """
  10. if isinstance(value, (float, complex) + six.integer_types):
  11. return True
  12. try:
  13. _ = (fabs(value) + 0 - 0) * 1
  14. return True
  15. except ArithmeticError:
  16. return True
  17. except:
  18. return False
  19. return False
  20. class IsCloseTo(BaseMatcher):
  21. def __init__(self, value, delta):
  22. if not isnumeric(value):
  23. raise TypeError('IsCloseTo value must be numeric')
  24. if not isnumeric(delta):
  25. raise TypeError('IsCloseTo delta must be numeric')
  26. self.value = value
  27. self.delta = delta
  28. def _matches(self, item):
  29. if not isnumeric(item):
  30. return False
  31. return fabs(item - self.value) <= self.delta
  32. def describe_mismatch(self, item, mismatch_description):
  33. if not isnumeric(item):
  34. super(IsCloseTo, self).describe_mismatch(item, mismatch_description)
  35. else:
  36. actual_delta = fabs(item - self.value)
  37. mismatch_description.append_description_of(item) \
  38. .append_text(' differed by ') \
  39. .append_description_of(actual_delta)
  40. def describe_to(self, description):
  41. description.append_text('a numeric value within ') \
  42. .append_description_of(self.delta) \
  43. .append_text(' of ') \
  44. .append_description_of(self.value)
  45. def close_to(value, delta):
  46. """Matches if object is a number close to a given value, within a given
  47. delta.
  48. :param value: The value to compare against as the expected value.
  49. :param delta: The maximum delta between the values for which the numbers
  50. are considered close.
  51. This matcher compares the evaluated object against ``value`` to see if the
  52. difference is within a positive ``delta``.
  53. Example::
  54. close_to(3.0, 0.25)
  55. """
  56. return IsCloseTo(value, delta)