smartdict.py revision 1530
1# The SmartDict class fixes a couple of issues with using the content
2# of os.environ or similar dicts of strings as Python variables:
3#
4# 1) Undefined variables should return False rather than raising KeyError.
5#
6# 2) String values of 'False', '0', etc., should evaluate to False
7#    (not just the empty string).
8#
9# #1 is solved by overriding __getitem__, and #2 is solved by using a
10# proxy class for values and overriding __nonzero__ on the proxy.
11# Everything else is just to (a) make proxies behave like normal
12# values otherwise, (b) make sure any dict operation returns a proxy
13# rather than a normal value, and (c) coerce values written to the
14# dict to be strings.
15
16
17from convert import *
18
19class SmartDict(dict):
20
21    class Proxy(str):
22        def __int__(self):
23            return int(to_integer(str(self)))
24        def __long__(self):
25            return long(to_integer(str(self)))
26        def __float__(self):
27            return float(to_integer(str(self)))
28        def __nonzero__(self):
29            return to_bool(str(self))
30        def convert(self, other):
31            t = type(other)
32            if t == bool:
33                return bool(self)
34            if t == int:
35                return int(self)
36            if t == long:
37                return long(self)
38            if t == float:
39                return float(self)
40            return str(self)
41        def __lt__(self, other):
42            return self.convert(other) < other
43        def __le__(self, other):
44            return self.convert(other) <= other
45        def __eq__(self, other):
46            return self.convert(other) == other
47        def __ne__(self, other):
48            return self.convert(other) != other
49        def __gt__(self, other):
50            return self.convert(other) > other
51        def __ge__(self, other):
52            return self.convert(other) >= other
53
54        def __add__(self, other):
55            return self.convert(other) + other
56        def __sub__(self, other):
57            return self.convert(other) - other
58        def __mul__(self, other):
59            return self.convert(other) * other
60        def __div__(self, other):
61            return self.convert(other) / other
62        def __truediv__(self, other):
63            return self.convert(other) / other
64
65        def __radd__(self, other):
66            return other + self.convert(other)
67        def __rsub__(self, other):
68            return other - self.convert(other)
69        def __rmul__(self, other):
70            return other * self.convert(other)
71        def __rdiv__(self, other):
72            return other / self.convert(other)
73        def __rtruediv__(self, other):
74            return other / self.convert(other)
75
76
77    def __getitem__(self, key):
78        return self.Proxy(dict.get(self, key, 'False'))
79
80    def __setitem__(self, key, item):
81        dict.__setitem__(self, key, str(item))
82
83    def values(self):
84        return [ self.Proxy(v) for v in dict.values(self) ]
85
86    def itervalues(self):
87        for value in dict.itervalues(self):
88            yield self.Proxy(value)
89
90    def items(self):
91        return [ (k, self.Proxy(v)) for k,v in dict.items(self) ]
92
93    def iteritems(self):
94        for key,value in dict.iteritems(self):
95            yield key, self.Proxy(value)
96
97    def get(self, key, default='False'):
98        return self.Proxy(dict.get(self, key, str(default)))
99
100    def setdefault(self, key, default='False'):
101        return self.Proxy(dict.setdefault(self, key, str(default)))
102
103