-
Notifications
You must be signed in to change notification settings - Fork 2
/
_attr.py
102 lines (69 loc) · 2.83 KB
/
_attr.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#!/usr/bin/env python
# Steven Phillips / elimisteve
# 2015.04.24
def get_attr(dict_or_obj, *attrs):
ATTR_NOT_FOUND = KeyError("{} doesn't have attr(s) {}".format(dict_or_obj, attrs))
if isinstance(dict_or_obj, dict):
for attr in attrs:
if attr in dict_or_obj:
return dict_or_obj[attr], attr
raise ATTR_NOT_FOUND
for attr in attrs:
if hasattr(dict_or_obj, attr):
return getattr(dict_or_obj, attr), attr
raise ATTR_NOT_FOUND
def has_attr(dict_or_obj, attr):
if isinstance(dict_or_obj, dict):
return attr in dict_or_obj
# Assuming it's an object
return hasattr(dict_or_obj, attr)
def has_method(obj, method_name):
# If the attribute is callable, it's a method, otherwise it's a
# property
return hasattr(obj, method_name) and callable(getattr(obj, method_name))
def update_object(obj, kwargs):
for k in kwargs:
setattr(obj, k, kwargs[k])
collection_types = (list, tuple, set, frozenset)
def is_collection(coll):
return any([ isinstance(coll, typ) for typ in collection_types ])
def Is(obj, attr_value):
'''
Meant to capture the following senses of 'is':
- Snow is white, George W. Bush is Republican, this desk is wood,
etc (object `obj` has some attribute `a`, or has an attribute
with a value of `a`.)
- Santa Claus is Santa Claus, 2 + 2 is 4, etc (identity)
Not done yet:
- 2 is even (search for an `is_even` function and see if is_even(2) == True)
'''
#
# TODO(elimisteve): Consider leaving this notion of 'is' out
#
# if type(obj) == type(attr_value):
# return obj is attr_value
# TODO(elimisteve): Questionable. Should string comparisons work?
if isinstance(obj, str) and isinstance(attr_value, str):
return obj is attr_value
# If they're not both strings, assume they're both objects and compare
if type(obj) != str and type(attr_value) != str:
# TODO(elimisteve): Could use `==` instead of `is` here, especially
# to make dict comparisons match... but it's not clear that
# that would be the right behavior; shouldn't a custom __eq__
# method be defined in that case, a custom equals() method
# function, or similar?
return obj is attr_value
assert type(obj) != str
assert type(attr_value) == str
# Check for `obj.something == attr_value`
matches_value = any([ v == attr_value or is_collection(v) and attr_value in v
for v in obj.__dict__.values() ])
if matches_value:
return True
# Check for `obj.attr_value is True`
if has_attr(obj, attr_value) and get_attr(obj, attr_value)[0] is True:
return True
return False
# Does(some_object, 'exists') is probably less awkward than
# Is(some_object, 'exists'). Maybe.
##Does = Is