Completed
Pull Request — master (#75)
by Cézar
01:32
created

src.hamcrest.library.number.IsCloseTo   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 30
Duplicated Lines 0 %
Metric Value
dl 0
loc 30
rs 10
wmc 8

4 Methods

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