smartdict.py revision 6997
11736SN/A# Copyright (c) 2005 The Regents of The University of Michigan
21736SN/A# All rights reserved.
31736SN/A#
41736SN/A# Redistribution and use in source and binary forms, with or without
51736SN/A# modification, are permitted provided that the following conditions are
61736SN/A# met: redistributions of source code must retain the above copyright
71736SN/A# notice, this list of conditions and the following disclaimer;
81736SN/A# redistributions in binary form must reproduce the above copyright
91736SN/A# notice, this list of conditions and the following disclaimer in the
101736SN/A# documentation and/or other materials provided with the distribution;
111736SN/A# neither the name of the copyright holders nor the names of its
121736SN/A# contributors may be used to endorse or promote products derived from
131736SN/A# this software without specific prior written permission.
141736SN/A#
151736SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
161736SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
171736SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
181736SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
191736SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
201736SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
211736SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
221736SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
231736SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
241736SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
251736SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
262665SN/A#
272665SN/A# Authors: Nathan Binkert
281736SN/A
291530SN/A# The SmartDict class fixes a couple of issues with using the content
301530SN/A# of os.environ or similar dicts of strings as Python variables:
311530SN/A#
321530SN/A# 1) Undefined variables should return False rather than raising KeyError.
331530SN/A#
341530SN/A# 2) String values of 'False', '0', etc., should evaluate to False
351530SN/A#    (not just the empty string).
361530SN/A#
371530SN/A# #1 is solved by overriding __getitem__, and #2 is solved by using a
381530SN/A# proxy class for values and overriding __nonzero__ on the proxy.
391530SN/A# Everything else is just to (a) make proxies behave like normal
401530SN/A# values otherwise, (b) make sure any dict operation returns a proxy
411530SN/A# rather than a normal value, and (c) coerce values written to the
421530SN/A# dict to be strings.
431530SN/A
441530SN/A
451519SN/Afrom convert import *
466997Snate@binkert.orgfrom attrdict import attrdict
471519SN/A
481606SN/Aclass Variable(str):
491606SN/A    """Intelligent proxy class for SmartDict.  Variable will use the
501606SN/A    various convert functions to attempt to convert values to useable
511606SN/A    types"""
521606SN/A    def __int__(self):
531606SN/A        return toInteger(str(self))
541606SN/A    def __long__(self):
551606SN/A        return toLong(str(self))
561606SN/A    def __float__(self):
571606SN/A        return toFloat(str(self))
581606SN/A    def __nonzero__(self):
591606SN/A        return toBool(str(self))
601606SN/A    def convert(self, other):
611606SN/A        t = type(other)
621606SN/A        if t == bool:
631606SN/A            return bool(self)
641606SN/A        if t == int:
651606SN/A            return int(self)
661606SN/A        if t == long:
671606SN/A            return long(self)
681606SN/A        if t == float:
691606SN/A            return float(self)
701606SN/A        return str(self)
711606SN/A    def __lt__(self, other):
721606SN/A        return self.convert(other) < other
731606SN/A    def __le__(self, other):
741606SN/A        return self.convert(other) <= other
751606SN/A    def __eq__(self, other):
761606SN/A        return self.convert(other) == other
771606SN/A    def __ne__(self, other):
781606SN/A        return self.convert(other) != other
791606SN/A    def __gt__(self, other):
801606SN/A        return self.convert(other) > other
811606SN/A    def __ge__(self, other):
821606SN/A        return self.convert(other) >= other
831606SN/A
841606SN/A    def __add__(self, other):
851606SN/A        return self.convert(other) + other
861606SN/A    def __sub__(self, other):
871606SN/A        return self.convert(other) - other
881606SN/A    def __mul__(self, other):
891606SN/A        return self.convert(other) * other
901606SN/A    def __div__(self, other):
911606SN/A        return self.convert(other) / other
921606SN/A    def __truediv__(self, other):
931606SN/A        return self.convert(other) / other
941606SN/A
951606SN/A    def __radd__(self, other):
961606SN/A        return other + self.convert(other)
971606SN/A    def __rsub__(self, other):
981606SN/A        return other - self.convert(other)
991606SN/A    def __rmul__(self, other):
1001606SN/A        return other * self.convert(other)
1011606SN/A    def __rdiv__(self, other):
1021606SN/A        return other / self.convert(other)
1031606SN/A    def __rtruediv__(self, other):
1041606SN/A        return other / self.convert(other)
1051606SN/A
1061606SN/Aclass UndefinedVariable(object):
1071606SN/A    """Placeholder class to represent undefined variables.  Will
1081606SN/A    generally cause an exception whenever it is used, but evaluates to
1091606SN/A    zero for boolean truth testing such as in an if statement"""
1101606SN/A    def __nonzero__(self):
1111606SN/A        return False
1121606SN/A
1136997Snate@binkert.orgclass SmartDict(attrdict):
1141606SN/A    """Dictionary class that holds strings, but intelligently converts
1151606SN/A    those strings to other types depending on their usage"""
1161530SN/A
1171606SN/A    def __getitem__(self, key):
1181606SN/A        """returns a Variable proxy if the values exists in the database and
1191606SN/A        returns an UndefinedVariable otherwise"""
1201519SN/A
1211606SN/A        if key in self:
1221606SN/A            return Variable(dict.get(self, key))
1231606SN/A        else:
1241606SN/A            # Note that this does *not* change the contents of the dict,
1251606SN/A            # so that even after we call env['foo'] we still get a
1261606SN/A            # meaningful answer from "'foo' in env" (which
1271606SN/A            # calls dict.__contains__, which we do not override).
1281606SN/A            return UndefinedVariable()
1291519SN/A
1301519SN/A    def __setitem__(self, key, item):
1311606SN/A        """intercept the setting of any variable so that we always
1321606SN/A        store strings in the dict"""
1331519SN/A        dict.__setitem__(self, key, str(item))
1341519SN/A
1351519SN/A    def values(self):
1361606SN/A        return [ Variable(v) for v in dict.values(self) ]
1371519SN/A
1381519SN/A    def itervalues(self):
1391519SN/A        for value in dict.itervalues(self):
1401606SN/A            yield Variable(value)
1411519SN/A
1421519SN/A    def items(self):
1431606SN/A        return [ (k, Variable(v)) for k,v in dict.items(self) ]
1441519SN/A
1451519SN/A    def iteritems(self):
1461519SN/A        for key,value in dict.iteritems(self):
1471606SN/A            yield key, Variable(value)
1481519SN/A
1491530SN/A    def get(self, key, default='False'):
1501606SN/A        return Variable(dict.get(self, key, str(default)))
1511519SN/A
1521530SN/A    def setdefault(self, key, default='False'):
1531606SN/A        return Variable(dict.setdefault(self, key, str(default)))
1541519SN/A
1551606SN/A__all__ = [ 'SmartDict' ]
156