smartdict.py revision 13714:35636064b7a1
13395Shsul@eecs.umich.edu# Copyright (c) 2005 The Regents of The University of Michigan 23395Shsul@eecs.umich.edu# All rights reserved. 33395Shsul@eecs.umich.edu# 43395Shsul@eecs.umich.edu# Redistribution and use in source and binary forms, with or without 53395Shsul@eecs.umich.edu# modification, are permitted provided that the following conditions are 63395Shsul@eecs.umich.edu# met: redistributions of source code must retain the above copyright 73395Shsul@eecs.umich.edu# notice, this list of conditions and the following disclaimer; 83395Shsul@eecs.umich.edu# redistributions in binary form must reproduce the above copyright 93395Shsul@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the 103395Shsul@eecs.umich.edu# documentation and/or other materials provided with the distribution; 113395Shsul@eecs.umich.edu# neither the name of the copyright holders nor the names of its 123395Shsul@eecs.umich.edu# contributors may be used to endorse or promote products derived from 133395Shsul@eecs.umich.edu# this software without specific prior written permission. 143395Shsul@eecs.umich.edu# 153395Shsul@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 163395Shsul@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 173395Shsul@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 183395Shsul@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 193395Shsul@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 203395Shsul@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 213395Shsul@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 223395Shsul@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 233395Shsul@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 243395Shsul@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 253395Shsul@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 263395Shsul@eecs.umich.edu# 273395Shsul@eecs.umich.edu# Authors: Nathan Binkert 283395Shsul@eecs.umich.edu 293395Shsul@eecs.umich.edu# The SmartDict class fixes a couple of issues with using the content 303509Shsul@eecs.umich.edu# of os.environ or similar dicts of strings as Python variables: 313395Shsul@eecs.umich.edu# 323395Shsul@eecs.umich.edu# 1) Undefined variables should return False rather than raising KeyError. 333395Shsul@eecs.umich.edu# 343448Shsul@eecs.umich.edu# 2) String values of 'False', '0', etc., should evaluate to False 353395Shsul@eecs.umich.edu# (not just the empty string). 363481Shsul@eecs.umich.edu# 373481Shsul@eecs.umich.edu# #1 is solved by overriding __getitem__, and #2 is solved by using a 383481Shsul@eecs.umich.edu# proxy class for values and overriding __nonzero__ on the proxy. 393481Shsul@eecs.umich.edu# Everything else is just to (a) make proxies behave like normal 403481Shsul@eecs.umich.edu# values otherwise, (b) make sure any dict operation returns a proxy 413481Shsul@eecs.umich.edu# rather than a normal value, and (c) coerce values written to the 423681Sktlim@umich.edu# dict to be strings. 433681Sktlim@umich.edu 443681Sktlim@umich.edufrom __future__ import print_function 453481Shsul@eecs.umich.edufrom __future__ import absolute_import 463481Shsul@eecs.umich.edu 473481Shsul@eecs.umich.edufrom .convert import * 483481Shsul@eecs.umich.edufrom .attrdict import attrdict 493481Shsul@eecs.umich.edu 503481Shsul@eecs.umich.educlass Variable(str): 513481Shsul@eecs.umich.edu """Intelligent proxy class for SmartDict. Variable will use the 523481Shsul@eecs.umich.edu various convert functions to attempt to convert values to useable 533481Shsul@eecs.umich.edu types""" 543481Shsul@eecs.umich.edu def __int__(self): 553481Shsul@eecs.umich.edu return toInteger(str(self)) 563481Shsul@eecs.umich.edu def __long__(self): 573481Shsul@eecs.umich.edu return toLong(str(self)) 583481Shsul@eecs.umich.edu def __float__(self): 593481Shsul@eecs.umich.edu return toFloat(str(self)) 603481Shsul@eecs.umich.edu def __bool__(self): 613481Shsul@eecs.umich.edu return toBool(str(self)) 623481Shsul@eecs.umich.edu # Python 2.7 uses __nonzero__ instead of __bool__ 633481Shsul@eecs.umich.edu __nonzero__ = __bool__ 643395Shsul@eecs.umich.edu def convert(self, other): 653395Shsul@eecs.umich.edu t = type(other) 663395Shsul@eecs.umich.edu if t == bool: 673395Shsul@eecs.umich.edu return bool(self) 683395Shsul@eecs.umich.edu if t == int: 693395Shsul@eecs.umich.edu return int(self) 703395Shsul@eecs.umich.edu if t == long: 713511Shsul@eecs.umich.edu return long(self) 723395Shsul@eecs.umich.edu if t == float: 733395Shsul@eecs.umich.edu return float(self) 743395Shsul@eecs.umich.edu return str(self) 753395Shsul@eecs.umich.edu def __lt__(self, other): 763395Shsul@eecs.umich.edu return self.convert(other) < other 773395Shsul@eecs.umich.edu def __le__(self, other): 783395Shsul@eecs.umich.edu return self.convert(other) <= other 793395Shsul@eecs.umich.edu def __eq__(self, other): 803481Shsul@eecs.umich.edu return self.convert(other) == other 813481Shsul@eecs.umich.edu def __ne__(self, other): 823481Shsul@eecs.umich.edu return self.convert(other) != other 833481Shsul@eecs.umich.edu def __gt__(self, other): 843481Shsul@eecs.umich.edu return self.convert(other) > other 853481Shsul@eecs.umich.edu def __ge__(self, other): 863481Shsul@eecs.umich.edu return self.convert(other) >= other 873481Shsul@eecs.umich.edu 883481Shsul@eecs.umich.edu def __add__(self, other): 893481Shsul@eecs.umich.edu return self.convert(other) + other 903481Shsul@eecs.umich.edu def __sub__(self, other): 913481Shsul@eecs.umich.edu return self.convert(other) - other 923481Shsul@eecs.umich.edu def __mul__(self, other): 933481Shsul@eecs.umich.edu return self.convert(other) * other 943395Shsul@eecs.umich.edu def __div__(self, other): 953395Shsul@eecs.umich.edu return self.convert(other) / other 963395Shsul@eecs.umich.edu def __truediv__(self, other): 973395Shsul@eecs.umich.edu return self.convert(other) / other 983478Shsul@eecs.umich.edu 993395Shsul@eecs.umich.edu def __radd__(self, other): 1003478Shsul@eecs.umich.edu return other + self.convert(other) 1013395Shsul@eecs.umich.edu def __rsub__(self, other): 1023395Shsul@eecs.umich.edu return other - self.convert(other) 1033478Shsul@eecs.umich.edu def __rmul__(self, other): 1043395Shsul@eecs.umich.edu return other * self.convert(other) 1053395Shsul@eecs.umich.edu def __rdiv__(self, other): 1063478Shsul@eecs.umich.edu return other / self.convert(other) 1073395Shsul@eecs.umich.edu def __rtruediv__(self, other): 1083478Shsul@eecs.umich.edu return other / self.convert(other) 1093480Shsul@eecs.umich.edu 1103514Sktlim@umich.educlass UndefinedVariable(object): 1113481Shsul@eecs.umich.edu """Placeholder class to represent undefined variables. Will 1123480Shsul@eecs.umich.edu generally cause an exception whenever it is used, but evaluates to 1133480Shsul@eecs.umich.edu zero for boolean truth testing such as in an if statement""" 1143480Shsul@eecs.umich.edu def __bool__(self): 1153395Shsul@eecs.umich.edu return False 1163478Shsul@eecs.umich.edu 1173514Sktlim@umich.edu # Python 2.7 uses __nonzero__ instead of __bool__ 1183514Sktlim@umich.edu __nonzero__ = __bool__ 1193395Shsul@eecs.umich.edu 1203478Shsul@eecs.umich.educlass SmartDict(attrdict): 1213395Shsul@eecs.umich.edu """Dictionary class that holds strings, but intelligently converts 1223395Shsul@eecs.umich.edu those strings to other types depending on their usage""" 1233395Shsul@eecs.umich.edu 1243395Shsul@eecs.umich.edu def __getitem__(self, key): 1253395Shsul@eecs.umich.edu """returns a Variable proxy if the values exists in the database and 1263395Shsul@eecs.umich.edu returns an UndefinedVariable otherwise""" 1273395Shsul@eecs.umich.edu 1283395Shsul@eecs.umich.edu if key in self: 1293395Shsul@eecs.umich.edu return Variable(dict.get(self, key)) 1303395Shsul@eecs.umich.edu else: 1313395Shsul@eecs.umich.edu # Note that this does *not* change the contents of the dict, 1323395Shsul@eecs.umich.edu # so that even after we call env['foo'] we still get a 1333395Shsul@eecs.umich.edu # meaningful answer from "'foo' in env" (which 1343395Shsul@eecs.umich.edu # calls dict.__contains__, which we do not override). 1353395Shsul@eecs.umich.edu return UndefinedVariable() 1363395Shsul@eecs.umich.edu 1373395Shsul@eecs.umich.edu def __setitem__(self, key, item): 1383395Shsul@eecs.umich.edu """intercept the setting of any variable so that we always 1393395Shsul@eecs.umich.edu store strings in the dict""" 1403395Shsul@eecs.umich.edu dict.__setitem__(self, key, str(item)) 1413395Shsul@eecs.umich.edu 1423395Shsul@eecs.umich.edu def values(self): 1433395Shsul@eecs.umich.edu for value in dict.values(self): 1443395Shsul@eecs.umich.edu yield Variable(value) 1453395Shsul@eecs.umich.edu 1463395Shsul@eecs.umich.edu def items(self): 1473395Shsul@eecs.umich.edu for key,value in dict.items(self): 1483509Shsul@eecs.umich.edu yield key, Variable(value) 1493395Shsul@eecs.umich.edu 1503481Shsul@eecs.umich.edu def get(self, key, default='False'): 1513395Shsul@eecs.umich.edu return Variable(dict.get(self, key, str(default))) 1523395Shsul@eecs.umich.edu 1533395Shsul@eecs.umich.edu def setdefault(self, key, default='False'): 1543395Shsul@eecs.umich.edu return Variable(dict.setdefault(self, key, str(default))) 1553395Shsul@eecs.umich.edu 1563395Shsul@eecs.umich.edu__all__ = [ 'SmartDict' ] 1573395Shsul@eecs.umich.edu