cb0cf2dd8a
--HG-- extra : convert_revision : 77f475b156d81c03a2811818fa23593d5615c685
154 lines
5.8 KiB
Python
154 lines
5.8 KiB
Python
# Copyright (c) 2005 The Regents of The University of Michigan
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions are
|
|
# met: redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer;
|
|
# redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution;
|
|
# neither the name of the copyright holders nor the names of its
|
|
# contributors may be used to endorse or promote products derived from
|
|
# this software without specific prior written permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
#
|
|
# Authors: Nathan Binkert
|
|
|
|
# The SmartDict class fixes a couple of issues with using the content
|
|
# of os.environ or similar dicts of strings as Python variables:
|
|
#
|
|
# 1) Undefined variables should return False rather than raising KeyError.
|
|
#
|
|
# 2) String values of 'False', '0', etc., should evaluate to False
|
|
# (not just the empty string).
|
|
#
|
|
# #1 is solved by overriding __getitem__, and #2 is solved by using a
|
|
# proxy class for values and overriding __nonzero__ on the proxy.
|
|
# Everything else is just to (a) make proxies behave like normal
|
|
# values otherwise, (b) make sure any dict operation returns a proxy
|
|
# rather than a normal value, and (c) coerce values written to the
|
|
# dict to be strings.
|
|
|
|
|
|
from convert import *
|
|
|
|
class Variable(str):
|
|
"""Intelligent proxy class for SmartDict. Variable will use the
|
|
various convert functions to attempt to convert values to useable
|
|
types"""
|
|
def __int__(self):
|
|
return toInteger(str(self))
|
|
def __long__(self):
|
|
return toLong(str(self))
|
|
def __float__(self):
|
|
return toFloat(str(self))
|
|
def __nonzero__(self):
|
|
return toBool(str(self))
|
|
def convert(self, other):
|
|
t = type(other)
|
|
if t == bool:
|
|
return bool(self)
|
|
if t == int:
|
|
return int(self)
|
|
if t == long:
|
|
return long(self)
|
|
if t == float:
|
|
return float(self)
|
|
return str(self)
|
|
def __lt__(self, other):
|
|
return self.convert(other) < other
|
|
def __le__(self, other):
|
|
return self.convert(other) <= other
|
|
def __eq__(self, other):
|
|
return self.convert(other) == other
|
|
def __ne__(self, other):
|
|
return self.convert(other) != other
|
|
def __gt__(self, other):
|
|
return self.convert(other) > other
|
|
def __ge__(self, other):
|
|
return self.convert(other) >= other
|
|
|
|
def __add__(self, other):
|
|
return self.convert(other) + other
|
|
def __sub__(self, other):
|
|
return self.convert(other) - other
|
|
def __mul__(self, other):
|
|
return self.convert(other) * other
|
|
def __div__(self, other):
|
|
return self.convert(other) / other
|
|
def __truediv__(self, other):
|
|
return self.convert(other) / other
|
|
|
|
def __radd__(self, other):
|
|
return other + self.convert(other)
|
|
def __rsub__(self, other):
|
|
return other - self.convert(other)
|
|
def __rmul__(self, other):
|
|
return other * self.convert(other)
|
|
def __rdiv__(self, other):
|
|
return other / self.convert(other)
|
|
def __rtruediv__(self, other):
|
|
return other / self.convert(other)
|
|
|
|
class UndefinedVariable(object):
|
|
"""Placeholder class to represent undefined variables. Will
|
|
generally cause an exception whenever it is used, but evaluates to
|
|
zero for boolean truth testing such as in an if statement"""
|
|
def __nonzero__(self):
|
|
return False
|
|
|
|
class SmartDict(dict):
|
|
"""Dictionary class that holds strings, but intelligently converts
|
|
those strings to other types depending on their usage"""
|
|
|
|
def __getitem__(self, key):
|
|
"""returns a Variable proxy if the values exists in the database and
|
|
returns an UndefinedVariable otherwise"""
|
|
|
|
if key in self:
|
|
return Variable(dict.get(self, key))
|
|
else:
|
|
# Note that this does *not* change the contents of the dict,
|
|
# so that even after we call env['foo'] we still get a
|
|
# meaningful answer from "'foo' in env" (which
|
|
# calls dict.__contains__, which we do not override).
|
|
return UndefinedVariable()
|
|
|
|
def __setitem__(self, key, item):
|
|
"""intercept the setting of any variable so that we always
|
|
store strings in the dict"""
|
|
dict.__setitem__(self, key, str(item))
|
|
|
|
def values(self):
|
|
return [ Variable(v) for v in dict.values(self) ]
|
|
|
|
def itervalues(self):
|
|
for value in dict.itervalues(self):
|
|
yield Variable(value)
|
|
|
|
def items(self):
|
|
return [ (k, Variable(v)) for k,v in dict.items(self) ]
|
|
|
|
def iteritems(self):
|
|
for key,value in dict.iteritems(self):
|
|
yield key, Variable(value)
|
|
|
|
def get(self, key, default='False'):
|
|
return Variable(dict.get(self, key, str(default)))
|
|
|
|
def setdefault(self, key, default='False'):
|
|
return Variable(dict.setdefault(self, key, str(default)))
|
|
|
|
__all__ = [ 'SmartDict' ]
|