smartdict.py revision 13697
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)) 5813697Sandreas.sandberg@arm.com def __bool__(self): 591606SN/A return toBool(str(self)) 6013697Sandreas.sandberg@arm.com # Python 2.7 uses __nonzero__ instead of __bool__ 6113697Sandreas.sandberg@arm.com __nonzero__ = __bool__ 621606SN/A def convert(self, other): 631606SN/A t = type(other) 641606SN/A if t == bool: 651606SN/A return bool(self) 661606SN/A if t == int: 671606SN/A return int(self) 681606SN/A if t == long: 691606SN/A return long(self) 701606SN/A if t == float: 711606SN/A return float(self) 721606SN/A return str(self) 731606SN/A def __lt__(self, other): 741606SN/A return self.convert(other) < other 751606SN/A def __le__(self, other): 761606SN/A return self.convert(other) <= other 771606SN/A def __eq__(self, other): 781606SN/A return self.convert(other) == other 791606SN/A def __ne__(self, other): 801606SN/A return self.convert(other) != other 811606SN/A def __gt__(self, other): 821606SN/A return self.convert(other) > other 831606SN/A def __ge__(self, other): 841606SN/A return self.convert(other) >= other 851606SN/A 861606SN/A def __add__(self, other): 871606SN/A return self.convert(other) + other 881606SN/A def __sub__(self, other): 891606SN/A return self.convert(other) - other 901606SN/A def __mul__(self, other): 911606SN/A return self.convert(other) * other 921606SN/A def __div__(self, other): 931606SN/A return self.convert(other) / other 941606SN/A def __truediv__(self, other): 951606SN/A return self.convert(other) / other 961606SN/A 971606SN/A def __radd__(self, other): 981606SN/A return other + self.convert(other) 991606SN/A def __rsub__(self, other): 1001606SN/A return other - self.convert(other) 1011606SN/A def __rmul__(self, other): 1021606SN/A return other * self.convert(other) 1031606SN/A def __rdiv__(self, other): 1041606SN/A return other / self.convert(other) 1051606SN/A def __rtruediv__(self, other): 1061606SN/A return other / self.convert(other) 1071606SN/A 1081606SN/Aclass UndefinedVariable(object): 1091606SN/A """Placeholder class to represent undefined variables. Will 1101606SN/A generally cause an exception whenever it is used, but evaluates to 1111606SN/A zero for boolean truth testing such as in an if statement""" 11213697Sandreas.sandberg@arm.com def __bool__(self): 1131606SN/A return False 1141606SN/A 11513697Sandreas.sandberg@arm.com # Python 2.7 uses __nonzero__ instead of __bool__ 11613697Sandreas.sandberg@arm.com __nonzero__ = __bool__ 11713697Sandreas.sandberg@arm.com 1186997Snate@binkert.orgclass SmartDict(attrdict): 1191606SN/A """Dictionary class that holds strings, but intelligently converts 1201606SN/A those strings to other types depending on their usage""" 1211530SN/A 1221606SN/A def __getitem__(self, key): 1231606SN/A """returns a Variable proxy if the values exists in the database and 1241606SN/A returns an UndefinedVariable otherwise""" 1251519SN/A 1261606SN/A if key in self: 1271606SN/A return Variable(dict.get(self, key)) 1281606SN/A else: 1291606SN/A # Note that this does *not* change the contents of the dict, 1301606SN/A # so that even after we call env['foo'] we still get a 1311606SN/A # meaningful answer from "'foo' in env" (which 1321606SN/A # calls dict.__contains__, which we do not override). 1331606SN/A return UndefinedVariable() 1341519SN/A 1351519SN/A def __setitem__(self, key, item): 1361606SN/A """intercept the setting of any variable so that we always 1371606SN/A store strings in the dict""" 1381519SN/A dict.__setitem__(self, key, str(item)) 1391519SN/A 1401519SN/A def values(self): 1411606SN/A return [ Variable(v) for v in dict.values(self) ] 1421519SN/A 1431519SN/A def itervalues(self): 1441519SN/A for value in dict.itervalues(self): 1451606SN/A yield Variable(value) 1461519SN/A 1471519SN/A def items(self): 1481606SN/A return [ (k, Variable(v)) for k,v in dict.items(self) ] 1491519SN/A 1501519SN/A def iteritems(self): 1511519SN/A for key,value in dict.iteritems(self): 1521606SN/A yield key, Variable(value) 1531519SN/A 1541530SN/A def get(self, key, default='False'): 1551606SN/A return Variable(dict.get(self, key, str(default))) 1561519SN/A 1571530SN/A def setdefault(self, key, default='False'): 1581606SN/A return Variable(dict.setdefault(self, key, str(default))) 1591519SN/A 1601606SN/A__all__ = [ 'SmartDict' ] 161