smartdict.py revision 13714:35636064b7a1
110428Sandreas.hansson@arm.com# Copyright (c) 2005 The Regents of The University of Michigan
210428Sandreas.hansson@arm.com# All rights reserved.
310428Sandreas.hansson@arm.com#
410428Sandreas.hansson@arm.com# Redistribution and use in source and binary forms, with or without
510428Sandreas.hansson@arm.com# modification, are permitted provided that the following conditions are
610428Sandreas.hansson@arm.com# met: redistributions of source code must retain the above copyright
710428Sandreas.hansson@arm.com# notice, this list of conditions and the following disclaimer;
810428Sandreas.hansson@arm.com# redistributions in binary form must reproduce the above copyright
910428Sandreas.hansson@arm.com# notice, this list of conditions and the following disclaimer in the
1010428Sandreas.hansson@arm.com# documentation and/or other materials provided with the distribution;
1110428Sandreas.hansson@arm.com# neither the name of the copyright holders nor the names of its
1210428Sandreas.hansson@arm.com# contributors may be used to endorse or promote products derived from
1310428Sandreas.hansson@arm.com# this software without specific prior written permission.
1410428Sandreas.hansson@arm.com#
1510428Sandreas.hansson@arm.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1610428Sandreas.hansson@arm.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1710428Sandreas.hansson@arm.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1810428Sandreas.hansson@arm.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1910428Sandreas.hansson@arm.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2010428Sandreas.hansson@arm.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2110428Sandreas.hansson@arm.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2210428Sandreas.hansson@arm.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2310428Sandreas.hansson@arm.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2410428Sandreas.hansson@arm.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2510428Sandreas.hansson@arm.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2610428Sandreas.hansson@arm.com#
2710428Sandreas.hansson@arm.com# Authors: Nathan Binkert
2810428Sandreas.hansson@arm.com
2910428Sandreas.hansson@arm.com# The SmartDict class fixes a couple of issues with using the content
3010428Sandreas.hansson@arm.com# of os.environ or similar dicts of strings as Python variables:
3110428Sandreas.hansson@arm.com#
3210428Sandreas.hansson@arm.com# 1) Undefined variables should return False rather than raising KeyError.
3310428Sandreas.hansson@arm.com#
3412266Sradhika.jagtap@arm.com# 2) String values of 'False', '0', etc., should evaluate to False
3512266Sradhika.jagtap@arm.com#    (not just the empty string).
3612266Sradhika.jagtap@arm.com#
3712266Sradhika.jagtap@arm.com# #1 is solved by overriding __getitem__, and #2 is solved by using a
3812266Sradhika.jagtap@arm.com# proxy class for values and overriding __nonzero__ on the proxy.
3912266Sradhika.jagtap@arm.com# Everything else is just to (a) make proxies behave like normal
4012266Sradhika.jagtap@arm.com# values otherwise, (b) make sure any dict operation returns a proxy
4110428Sandreas.hansson@arm.com# rather than a normal value, and (c) coerce values written to the
4210428Sandreas.hansson@arm.com# dict to be strings.
4310428Sandreas.hansson@arm.com
4410428Sandreas.hansson@arm.comfrom __future__ import print_function
4510428Sandreas.hansson@arm.comfrom __future__ import absolute_import
4610428Sandreas.hansson@arm.com
4710428Sandreas.hansson@arm.comfrom .convert import *
4810428Sandreas.hansson@arm.comfrom .attrdict import attrdict
4910428Sandreas.hansson@arm.com
5010428Sandreas.hansson@arm.comclass Variable(str):
5110428Sandreas.hansson@arm.com    """Intelligent proxy class for SmartDict.  Variable will use the
5210428Sandreas.hansson@arm.com    various convert functions to attempt to convert values to useable
5310428Sandreas.hansson@arm.com    types"""
5411555Sjungma@eit.uni-kl.de    def __int__(self):
5510428Sandreas.hansson@arm.com        return toInteger(str(self))
5611555Sjungma@eit.uni-kl.de    def __long__(self):
5711555Sjungma@eit.uni-kl.de        return toLong(str(self))
5811555Sjungma@eit.uni-kl.de    def __float__(self):
5911555Sjungma@eit.uni-kl.de        return toFloat(str(self))
6011555Sjungma@eit.uni-kl.de    def __bool__(self):
6110428Sandreas.hansson@arm.com        return toBool(str(self))
6210428Sandreas.hansson@arm.com    # Python 2.7 uses __nonzero__ instead of __bool__
6312266Sradhika.jagtap@arm.com    __nonzero__ = __bool__
6412266Sradhika.jagtap@arm.com    def convert(self, other):
6512266Sradhika.jagtap@arm.com        t = type(other)
6610428Sandreas.hansson@arm.com        if t == bool:
6712266Sradhika.jagtap@arm.com            return bool(self)
6810428Sandreas.hansson@arm.com        if t == int:
6912266Sradhika.jagtap@arm.com            return int(self)
7012266Sradhika.jagtap@arm.com        if t == long:
7112266Sradhika.jagtap@arm.com            return long(self)
7212266Sradhika.jagtap@arm.com        if t == float:
7312266Sradhika.jagtap@arm.com            return float(self)
7412266Sradhika.jagtap@arm.com        return str(self)
7512266Sradhika.jagtap@arm.com    def __lt__(self, other):
7612266Sradhika.jagtap@arm.com        return self.convert(other) < other
7712266Sradhika.jagtap@arm.com    def __le__(self, other):
7811555Sjungma@eit.uni-kl.de        return self.convert(other) <= other
7911555Sjungma@eit.uni-kl.de    def __eq__(self, other):
8011555Sjungma@eit.uni-kl.de        return self.convert(other) == other
8112266Sradhika.jagtap@arm.com    def __ne__(self, other):
8212266Sradhika.jagtap@arm.com        return self.convert(other) != other
8312266Sradhika.jagtap@arm.com    def __gt__(self, other):
8411555Sjungma@eit.uni-kl.de        return self.convert(other) > other
8511555Sjungma@eit.uni-kl.de    def __ge__(self, other):
8611555Sjungma@eit.uni-kl.de        return self.convert(other) >= other
8712266Sradhika.jagtap@arm.com
8812266Sradhika.jagtap@arm.com    def __add__(self, other):
8911555Sjungma@eit.uni-kl.de        return self.convert(other) + other
9011555Sjungma@eit.uni-kl.de    def __sub__(self, other):
9111555Sjungma@eit.uni-kl.de        return self.convert(other) - other
9211555Sjungma@eit.uni-kl.de    def __mul__(self, other):
9311555Sjungma@eit.uni-kl.de        return self.convert(other) * other
9412266Sradhika.jagtap@arm.com    def __div__(self, other):
9512266Sradhika.jagtap@arm.com        return self.convert(other) / other
9612266Sradhika.jagtap@arm.com    def __truediv__(self, other):
9712266Sradhika.jagtap@arm.com        return self.convert(other) / other
9812266Sradhika.jagtap@arm.com
9910428Sandreas.hansson@arm.com    def __radd__(self, other):
10010428Sandreas.hansson@arm.com        return other + self.convert(other)
10110428Sandreas.hansson@arm.com    def __rsub__(self, other):
10210428Sandreas.hansson@arm.com        return other - self.convert(other)
10310428Sandreas.hansson@arm.com    def __rmul__(self, other):
10410428Sandreas.hansson@arm.com        return other * self.convert(other)
10510428Sandreas.hansson@arm.com    def __rdiv__(self, other):
10610428Sandreas.hansson@arm.com        return other / self.convert(other)
10710428Sandreas.hansson@arm.com    def __rtruediv__(self, other):
10810428Sandreas.hansson@arm.com        return other / self.convert(other)
10910428Sandreas.hansson@arm.com
11010428Sandreas.hansson@arm.comclass UndefinedVariable(object):
11110428Sandreas.hansson@arm.com    """Placeholder class to represent undefined variables.  Will
11210428Sandreas.hansson@arm.com    generally cause an exception whenever it is used, but evaluates to
11310428Sandreas.hansson@arm.com    zero for boolean truth testing such as in an if statement"""
11410428Sandreas.hansson@arm.com    def __bool__(self):
11510428Sandreas.hansson@arm.com        return False
11610428Sandreas.hansson@arm.com
11710428Sandreas.hansson@arm.com    # Python 2.7 uses __nonzero__ instead of __bool__
11810428Sandreas.hansson@arm.com    __nonzero__ = __bool__
11910428Sandreas.hansson@arm.com
12010428Sandreas.hansson@arm.comclass SmartDict(attrdict):
12110428Sandreas.hansson@arm.com    """Dictionary class that holds strings, but intelligently converts
12210428Sandreas.hansson@arm.com    those strings to other types depending on their usage"""
12310428Sandreas.hansson@arm.com
12411555Sjungma@eit.uni-kl.de    def __getitem__(self, key):
12511555Sjungma@eit.uni-kl.de        """returns a Variable proxy if the values exists in the database and
12612266Sradhika.jagtap@arm.com        returns an UndefinedVariable otherwise"""
12711555Sjungma@eit.uni-kl.de
12812266Sradhika.jagtap@arm.com        if key in self:
12911555Sjungma@eit.uni-kl.de            return Variable(dict.get(self, key))
13012266Sradhika.jagtap@arm.com        else:
13112266Sradhika.jagtap@arm.com            # Note that this does *not* change the contents of the dict,
13211555Sjungma@eit.uni-kl.de            # so that even after we call env['foo'] we still get a
13311555Sjungma@eit.uni-kl.de            # meaningful answer from "'foo' in env" (which
13411555Sjungma@eit.uni-kl.de            # calls dict.__contains__, which we do not override).
13511555Sjungma@eit.uni-kl.de            return UndefinedVariable()
13610428Sandreas.hansson@arm.com
13710428Sandreas.hansson@arm.com    def __setitem__(self, key, item):
13810428Sandreas.hansson@arm.com        """intercept the setting of any variable so that we always
13911555Sjungma@eit.uni-kl.de        store strings in the dict"""
14012266Sradhika.jagtap@arm.com        dict.__setitem__(self, key, str(item))
14112266Sradhika.jagtap@arm.com
14212266Sradhika.jagtap@arm.com    def values(self):
14312266Sradhika.jagtap@arm.com        for value in dict.values(self):
14412266Sradhika.jagtap@arm.com            yield Variable(value)
14512266Sradhika.jagtap@arm.com
14611555Sjungma@eit.uni-kl.de    def items(self):
14712266Sradhika.jagtap@arm.com        for key,value in dict.items(self):
14812266Sradhika.jagtap@arm.com            yield key, Variable(value)
14912266Sradhika.jagtap@arm.com
15012266Sradhika.jagtap@arm.com    def get(self, key, default='False'):
15112266Sradhika.jagtap@arm.com        return Variable(dict.get(self, key, str(default)))
15212266Sradhika.jagtap@arm.com
15311555Sjungma@eit.uni-kl.de    def setdefault(self, key, default='False'):
15410428Sandreas.hansson@arm.com        return Variable(dict.setdefault(self, key, str(default)))
15510428Sandreas.hansson@arm.com
15610428Sandreas.hansson@arm.com__all__ = [ 'SmartDict' ]
15710428Sandreas.hansson@arm.com