Issues (6)

src/hamcrest/library/object/hasproperty.py (1 issue)

1
from hamcrest.core.base_matcher import BaseMatcher
2
from hamcrest.core import anything
3
from hamcrest.core.core.allof import all_of
4
from hamcrest.core.string_description import StringDescription
5
from hamcrest.core.helpers.hasmethod import hasmethod
6
from hamcrest.core.helpers.wrap_matcher import wrap_matcher as wrap_shortcut
7
8
__author__ = "Chris Rose"
9
__copyright__ = "Copyright 2011 hamcrest.org"
10
__license__ = "BSD, see License.txt"
11
12
13
class IsObjectWithProperty(BaseMatcher):
14
15
    def __init__(self, property_name, value_matcher):
16
        self.property_name = property_name
17
        self.value_matcher = value_matcher
18
19
    def _matches(self, o):
20
        if o is None:
21
            return False
22
23
        if not hasattr(o, self.property_name):
24
            return False
25
26
        value = getattr(o, self.property_name)
27
        return self.value_matcher.matches(value)
28
29
    def describe_to(self, description):
30
        description.append_text("an object with a property '") \
31
                                        .append_text(self.property_name) \
32
                                        .append_text("' matching ") \
33
                                        .append_description_of(self.value_matcher)
34
35
    def describe_mismatch(self, item, mismatch_description):
36
        if item is None:
37
            mismatch_description.append_text('was None')
38
            return
39
40
        if not hasattr(item, self.property_name):
41
            mismatch_description.append_value(item) \
42
                                                    .append_text(' did not have the ') \
43
                                                    .append_value(self.property_name) \
44
                                                    .append_text(' property')
45
            return
46
47
        mismatch_description.append_text('property ').append_value(self.property_name).append_text(' ')
48
        value = getattr(item, self.property_name)
49
        self.value_matcher.describe_mismatch(value, mismatch_description)
50
51
    def __str__(self):
52
        d = StringDescription()
53
        self.describe_to(d)
54
        return str(d)
55
56
57
def has_property(name, match=None):
58
    """Matches if object has a property with a given name whose value satisfies
59
    a given matcher.
60
61
    :param name: The name of the property.
62
    :param match: Optional matcher to satisfy.
63
64
    This matcher determines if the evaluated object has a property with a given
65
    name. If no such property is found, ``has_property`` is not satisfied.
66
67
    If the property is found, its value is passed to a given matcher for
68
    evaluation. If the ``match`` argument is not a matcher, it is implicitly
69
    wrapped in an :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to
70
    check for equality.
71
72
    If the ``match`` argument is not provided, the
73
    :py:func:`~hamcrest.core.core.isanything.anything` matcher is used so that
74
    ``has_property`` is satisfied if a matching property is found.
75
76
    Examples::
77
78
        has_property('name', starts_with('J'))
79
        has_property('name', 'Jon')
80
        has_property('name')
81
82
    """
83
84
    if match is None:
85
        match = anything()
86
87
    return IsObjectWithProperty(name, wrap_shortcut(match))
88
89
90
def has_properties(*keys_valuematchers, **kv_args):
91
    """Matches if an object has properties satisfying all of a dictionary
92
    of string property names and corresponding value matchers.
93
94
    :param matcher_dict: A dictionary mapping keys to associated value matchers,
95
        or to expected values for
96
        :py:func:`~hamcrest.core.core.isequal.equal_to` matching.
97
98
    Note that the keys must be actual keys, not matchers. Any value argument
99
    that is not a matcher is implicitly wrapped in an
100
    :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for
101
    equality.
102
103
    Examples::
104
105
        has_properties({'foo':equal_to(1), 'bar':equal_to(2)})
106
        has_properties({'foo':1, 'bar':2})
107
108
    ``has_properties`` also accepts a list of keyword arguments:
109
110
    .. function:: has_properties(keyword1=value_matcher1[, keyword2=value_matcher2[, ...]])
111
112
    :param keyword1: A keyword to look up.
113
    :param valueMatcher1: The matcher to satisfy for the value, or an expected
114
        value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching.
115
116
    Examples::
117
118
        has_properties(foo=equal_to(1), bar=equal_to(2))
119
        has_properties(foo=1, bar=2)
120
121
    Finally, ``has_properties`` also accepts a list of alternating keys and their
122
    value matchers:
123
124
    .. function:: has_properties(key1, value_matcher1[, ...])
125
126
    :param key1: A key (not a matcher) to look up.
127
    :param valueMatcher1: The matcher to satisfy for the value, or an expected
128
        value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching.
129
130
    Examples::
131
132
        has_properties('foo', equal_to(1), 'bar', equal_to(2))
133
        has_properties('foo', 1, 'bar', 2)
134
135
    """
136
    if len(keys_valuematchers) == 1:
0 ignored issues
show
This code seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
137
        try:
138
            base_dict = keys_valuematchers[0].copy()
139
            for key in base_dict:
140
                base_dict[key] = wrap_shortcut(base_dict[key])
141
        except AttributeError:
142
            raise ValueError('single-argument calls to has_properties must pass a dict as the argument')
143
    else:
144
        if len(keys_valuematchers) % 2:
145
            raise ValueError('has_properties requires key-value pairs')
146
        base_dict = {}
147
        for index in range(int(len(keys_valuematchers) / 2)):
148
            base_dict[keys_valuematchers[2 * index]] = wrap_shortcut(keys_valuematchers[2 * index + 1])
149
150
    for key, value in kv_args.items():
151
        base_dict[key] = wrap_shortcut(value)
152
153
    return all_of(*[has_property(property_name, property_value_matcher) for \
154
                   property_name, property_value_matcher in base_dict.items()])
155