1 # Copyright (c) 2005 The Regents of The University of Michigan
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met: redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer;
8 # redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution;
11 # neither the name of the copyright holders nor the names of its
12 # contributors may be used to endorse or promote products derived from
13 # this software without specific prior written permission.
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 # Authors: Nathan Binkert
29 # The SmartDict class fixes a couple of issues with using the content
30 # of os.environ or similar dicts of strings as Python variables:
32 # 1) Undefined variables should return False rather than raising KeyError.
34 # 2) String values of 'False', '0', etc., should evaluate to False
35 # (not just the empty string).
37 # #1 is solved by overriding __getitem__, and #2 is solved by using a
38 # proxy class for values and overriding __nonzero__ on the proxy.
39 # Everything else is just to (a) make proxies behave like normal
40 # values otherwise, (b) make sure any dict operation returns a proxy
41 # rather than a normal value, and (c) coerce values written to the
48 """Intelligent proxy class for SmartDict. Variable will use the
49 various convert functions to attempt to convert values to useable
52 return toInteger(str(self
))
54 return toLong(str(self
))
56 return toFloat(str(self
))
57 def __nonzero__(self
):
58 return toBool(str(self
))
59 def convert(self
, other
):
70 def __lt__(self
, other
):
71 return self
.convert(other
) < other
72 def __le__(self
, other
):
73 return self
.convert(other
) <= other
74 def __eq__(self
, other
):
75 return self
.convert(other
) == other
76 def __ne__(self
, other
):
77 return self
.convert(other
) != other
78 def __gt__(self
, other
):
79 return self
.convert(other
) > other
80 def __ge__(self
, other
):
81 return self
.convert(other
) >= other
83 def __add__(self
, other
):
84 return self
.convert(other
) + other
85 def __sub__(self
, other
):
86 return self
.convert(other
) - other
87 def __mul__(self
, other
):
88 return self
.convert(other
) * other
89 def __div__(self
, other
):
90 return self
.convert(other
) / other
91 def __truediv__(self
, other
):
92 return self
.convert(other
) / other
94 def __radd__(self
, other
):
95 return other
+ self
.convert(other
)
96 def __rsub__(self
, other
):
97 return other
- self
.convert(other
)
98 def __rmul__(self
, other
):
99 return other
* self
.convert(other
)
100 def __rdiv__(self
, other
):
101 return other
/ self
.convert(other
)
102 def __rtruediv__(self
, other
):
103 return other
/ self
.convert(other
)
105 class UndefinedVariable(object):
106 """Placeholder class to represent undefined variables. Will
107 generally cause an exception whenever it is used, but evaluates to
108 zero for boolean truth testing such as in an if statement"""
109 def __nonzero__(self
):
112 class SmartDict(dict):
113 """Dictionary class that holds strings, but intelligently converts
114 those strings to other types depending on their usage"""
116 def __getitem__(self
, key
):
117 """returns a Variable proxy if the values exists in the database and
118 returns an UndefinedVariable otherwise"""
121 return Variable(dict.get(self
, key
))
123 # Note that this does *not* change the contents of the dict,
124 # so that even after we call env['foo'] we still get a
125 # meaningful answer from "'foo' in env" (which
126 # calls dict.__contains__, which we do not override).
127 return UndefinedVariable()
129 def __setitem__(self
, key
, item
):
130 """intercept the setting of any variable so that we always
131 store strings in the dict"""
132 dict.__setitem
__(self
, key
, str(item
))
135 return [ Variable(v
) for v
in dict.values(self
) ]
137 def itervalues(self
):
138 for value
in dict.itervalues(self
):
139 yield Variable(value
)
142 return [ (k
, Variable(v
)) for k
,v
in dict.items(self
) ]
145 for key
,value
in dict.iteritems(self
):
146 yield key
, Variable(value
)
148 def get(self
, key
, default
='False'):
149 return Variable(dict.get(self
, key
, str(default
)))
151 def setdefault(self
, key
, default
='False'):
152 return Variable(dict.setdefault(self
, key
, str(default
)))
154 __all__
= [ 'SmartDict' ]