smartdict.py revision 13714
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 4413714Sandreas.sandberg@arm.comfrom __future__ import print_function 4513714Sandreas.sandberg@arm.comfrom __future__ import absolute_import 461530SN/A 4713714Sandreas.sandberg@arm.comfrom .convert import * 4813714Sandreas.sandberg@arm.comfrom .attrdict import attrdict 491519SN/A 501606SN/Aclass Variable(str): 511606SN/A """Intelligent proxy class for SmartDict. Variable will use the 521606SN/A various convert functions to attempt to convert values to useable 531606SN/A types""" 541606SN/A def __int__(self): 551606SN/A return toInteger(str(self)) 561606SN/A def __long__(self): 571606SN/A return toLong(str(self)) 581606SN/A def __float__(self): 591606SN/A return toFloat(str(self)) 6013697Sandreas.sandberg@arm.com def __bool__(self): 611606SN/A return toBool(str(self)) 6213697Sandreas.sandberg@arm.com # Python 2.7 uses __nonzero__ instead of __bool__ 6313697Sandreas.sandberg@arm.com __nonzero__ = __bool__ 641606SN/A def convert(self, other): 651606SN/A t = type(other) 661606SN/A if t == bool: 671606SN/A return bool(self) 681606SN/A if t == int: 691606SN/A return int(self) 701606SN/A if t == long: 711606SN/A return long(self) 721606SN/A if t == float: 731606SN/A return float(self) 741606SN/A return str(self) 751606SN/A def __lt__(self, other): 761606SN/A return self.convert(other) < other 771606SN/A def __le__(self, other): 781606SN/A return self.convert(other) <= other 791606SN/A def __eq__(self, other): 801606SN/A return self.convert(other) == other 811606SN/A def __ne__(self, other): 821606SN/A return self.convert(other) != other 831606SN/A def __gt__(self, other): 841606SN/A return self.convert(other) > other 851606SN/A def __ge__(self, other): 861606SN/A return self.convert(other) >= other 871606SN/A 881606SN/A def __add__(self, other): 891606SN/A return self.convert(other) + other 901606SN/A def __sub__(self, other): 911606SN/A return self.convert(other) - other 921606SN/A def __mul__(self, other): 931606SN/A return self.convert(other) * other 941606SN/A def __div__(self, other): 951606SN/A return self.convert(other) / other 961606SN/A def __truediv__(self, other): 971606SN/A return self.convert(other) / other 981606SN/A 991606SN/A def __radd__(self, other): 1001606SN/A return other + self.convert(other) 1011606SN/A def __rsub__(self, other): 1021606SN/A return other - self.convert(other) 1031606SN/A def __rmul__(self, other): 1041606SN/A return other * self.convert(other) 1051606SN/A def __rdiv__(self, other): 1061606SN/A return other / self.convert(other) 1071606SN/A def __rtruediv__(self, other): 1081606SN/A return other / self.convert(other) 1091606SN/A 1101606SN/Aclass UndefinedVariable(object): 1111606SN/A """Placeholder class to represent undefined variables. Will 1121606SN/A generally cause an exception whenever it is used, but evaluates to 1131606SN/A zero for boolean truth testing such as in an if statement""" 11413697Sandreas.sandberg@arm.com def __bool__(self): 1151606SN/A return False 1161606SN/A 11713697Sandreas.sandberg@arm.com # Python 2.7 uses __nonzero__ instead of __bool__ 11813697Sandreas.sandberg@arm.com __nonzero__ = __bool__ 11913697Sandreas.sandberg@arm.com 1206997Snate@binkert.orgclass SmartDict(attrdict): 1211606SN/A """Dictionary class that holds strings, but intelligently converts 1221606SN/A those strings to other types depending on their usage""" 1231530SN/A 1241606SN/A def __getitem__(self, key): 1251606SN/A """returns a Variable proxy if the values exists in the database and 1261606SN/A returns an UndefinedVariable otherwise""" 1271519SN/A 1281606SN/A if key in self: 1291606SN/A return Variable(dict.get(self, key)) 1301606SN/A else: 1311606SN/A # Note that this does *not* change the contents of the dict, 1321606SN/A # so that even after we call env['foo'] we still get a 1331606SN/A # meaningful answer from "'foo' in env" (which 1341606SN/A # calls dict.__contains__, which we do not override). 1351606SN/A return UndefinedVariable() 1361519SN/A 1371519SN/A def __setitem__(self, key, item): 1381606SN/A """intercept the setting of any variable so that we always 1391606SN/A store strings in the dict""" 1401519SN/A dict.__setitem__(self, key, str(item)) 1411519SN/A 1421519SN/A def values(self): 14313709Sandreas.sandberg@arm.com for value in dict.values(self): 1441606SN/A yield Variable(value) 1451519SN/A 1461519SN/A def items(self): 14713709Sandreas.sandberg@arm.com for key,value in dict.items(self): 1481606SN/A yield key, Variable(value) 1491519SN/A 1501530SN/A def get(self, key, default='False'): 1511606SN/A return Variable(dict.get(self, key, str(default))) 1521519SN/A 1531530SN/A def setdefault(self, key, default='False'): 1541606SN/A return Variable(dict.setdefault(self, key, str(default))) 1551519SN/A 1561606SN/A__all__ = [ 'SmartDict' ] 157