smartdict.py revision 13719
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 4613719Sandreas.sandberg@arm.comimport six 4713719Sandreas.sandberg@arm.comif six.PY3: 4813719Sandreas.sandberg@arm.com long = int 491530SN/A 5013714Sandreas.sandberg@arm.comfrom .convert import * 5113714Sandreas.sandberg@arm.comfrom .attrdict import attrdict 521519SN/A 531606SN/Aclass Variable(str): 541606SN/A """Intelligent proxy class for SmartDict. Variable will use the 551606SN/A various convert functions to attempt to convert values to useable 561606SN/A types""" 571606SN/A def __int__(self): 581606SN/A return toInteger(str(self)) 591606SN/A def __long__(self): 601606SN/A return toLong(str(self)) 611606SN/A def __float__(self): 621606SN/A return toFloat(str(self)) 6313697Sandreas.sandberg@arm.com def __bool__(self): 641606SN/A return toBool(str(self)) 6513697Sandreas.sandberg@arm.com # Python 2.7 uses __nonzero__ instead of __bool__ 6613697Sandreas.sandberg@arm.com __nonzero__ = __bool__ 671606SN/A def convert(self, other): 681606SN/A t = type(other) 691606SN/A if t == bool: 701606SN/A return bool(self) 711606SN/A if t == int: 721606SN/A return int(self) 731606SN/A if t == long: 741606SN/A return long(self) 751606SN/A if t == float: 761606SN/A return float(self) 771606SN/A return str(self) 781606SN/A def __lt__(self, other): 791606SN/A return self.convert(other) < other 801606SN/A def __le__(self, other): 811606SN/A return self.convert(other) <= other 821606SN/A def __eq__(self, other): 831606SN/A return self.convert(other) == other 841606SN/A def __ne__(self, other): 851606SN/A return self.convert(other) != other 861606SN/A def __gt__(self, other): 871606SN/A return self.convert(other) > other 881606SN/A def __ge__(self, other): 891606SN/A return self.convert(other) >= other 901606SN/A 911606SN/A def __add__(self, other): 921606SN/A return self.convert(other) + other 931606SN/A def __sub__(self, other): 941606SN/A return self.convert(other) - other 951606SN/A def __mul__(self, other): 961606SN/A return self.convert(other) * other 971606SN/A def __div__(self, other): 981606SN/A return self.convert(other) / other 991606SN/A def __truediv__(self, other): 1001606SN/A return self.convert(other) / other 1011606SN/A 1021606SN/A def __radd__(self, other): 1031606SN/A return other + self.convert(other) 1041606SN/A def __rsub__(self, other): 1051606SN/A return other - self.convert(other) 1061606SN/A def __rmul__(self, other): 1071606SN/A return other * self.convert(other) 1081606SN/A def __rdiv__(self, other): 1091606SN/A return other / self.convert(other) 1101606SN/A def __rtruediv__(self, other): 1111606SN/A return other / self.convert(other) 1121606SN/A 1131606SN/Aclass UndefinedVariable(object): 1141606SN/A """Placeholder class to represent undefined variables. Will 1151606SN/A generally cause an exception whenever it is used, but evaluates to 1161606SN/A zero for boolean truth testing such as in an if statement""" 11713697Sandreas.sandberg@arm.com def __bool__(self): 1181606SN/A return False 1191606SN/A 12013697Sandreas.sandberg@arm.com # Python 2.7 uses __nonzero__ instead of __bool__ 12113697Sandreas.sandberg@arm.com __nonzero__ = __bool__ 12213697Sandreas.sandberg@arm.com 1236997Snate@binkert.orgclass SmartDict(attrdict): 1241606SN/A """Dictionary class that holds strings, but intelligently converts 1251606SN/A those strings to other types depending on their usage""" 1261530SN/A 1271606SN/A def __getitem__(self, key): 1281606SN/A """returns a Variable proxy if the values exists in the database and 1291606SN/A returns an UndefinedVariable otherwise""" 1301519SN/A 1311606SN/A if key in self: 1321606SN/A return Variable(dict.get(self, key)) 1331606SN/A else: 1341606SN/A # Note that this does *not* change the contents of the dict, 1351606SN/A # so that even after we call env['foo'] we still get a 1361606SN/A # meaningful answer from "'foo' in env" (which 1371606SN/A # calls dict.__contains__, which we do not override). 1381606SN/A return UndefinedVariable() 1391519SN/A 1401519SN/A def __setitem__(self, key, item): 1411606SN/A """intercept the setting of any variable so that we always 1421606SN/A store strings in the dict""" 1431519SN/A dict.__setitem__(self, key, str(item)) 1441519SN/A 1451519SN/A def values(self): 14613709Sandreas.sandberg@arm.com for value in dict.values(self): 1471606SN/A yield Variable(value) 1481519SN/A 1491519SN/A def items(self): 15013709Sandreas.sandberg@arm.com for key,value in dict.items(self): 1511606SN/A yield key, Variable(value) 1521519SN/A 1531530SN/A def get(self, key, default='False'): 1541606SN/A return Variable(dict.get(self, key, str(default))) 1551519SN/A 1561530SN/A def setdefault(self, key, default='False'): 1571606SN/A return Variable(dict.setdefault(self, key, str(default))) 1581519SN/A 1591606SN/A__all__ = [ 'SmartDict' ] 160