Use the multidict in the python config stuff. Makes code a bit

cleaner.

python/m5/config.py:
    Use the multidict instead of the separately coded _getparam
    and _getvalue stuff.  While we're at it, when we see a default
    parameter, we stick it into the dictionary right away.

--HG--
extra : convert_revision : d6f6f5cc454a479e27718ec7952cd7559229ebe7
This commit is contained in:
Nathan Binkert 2005-03-22 00:53:01 -05:00
parent 62ce65c378
commit 3583fb6830
2 changed files with 213 additions and 121 deletions

View file

@ -29,6 +29,7 @@ import os, re, sys, types, inspect
from m5 import panic
from convert import *
from multidict import multidict
noDot = False
try:
@ -325,17 +326,22 @@ class MetaConfigNode(type):
super(MetaConfigNode, cls).__init__(name, bases, dict)
# initialize required attributes
cls._params = {}
cls._values = {}
cls._params = multidict()
cls._values = multidict()
cls._param_types = {}
cls._bases = [c for c in cls.__mro__ if isConfigNode(c)]
cls._anon_subclass_counter = 0
# If your parent has a value in it that's a config node, clone
# it. Do this now so if we update any of the values'
# attributes we are updating the clone and not the original.
for base in cls._bases:
for key,val in base._values.iteritems():
# We don't support multiple inheritence. If you want to, you
# must fix multidict to deal with it properly.
sob = [ base for base in bases \
if issubclass(base, ParamType) and base != ParamType ]
if len(sob) == 1:
# If your parent has a value in it that's a config node, clone
# it. Do this now so if we update any of the values'
# attributes we are updating the clone and not the original.
for key,val in sob[0]._values.iteritems():
# don't clone if (1) we're about to overwrite it with
# a local setting or (2) we've already cloned a copy
@ -345,12 +351,19 @@ class MetaConfigNode(type):
if isConfigNode(val):
cls._values[key] = val()
elif isSimObjSequence(val):
elif isSimObjSequence(val) and len(val):
cls._values[key] = [ v() for v in val ]
elif isNullPointer(val):
cls._values[key] = val
# process param types from _init_dict first, as these may be needed
cls._params.parent = sob[0]._params
cls._values.parent = sob[0]._values
elif len(sob) > 1:
panic("""\
The config hierarchy only supports single inheritence of SimObject
classes. You're trying to derive from:
%s""" % str(sob))
# process param types from _init_dict, as these may be needed
# by param descriptions also in _init_dict
for key,val in cls._init_dict.items():
if isinstance(val, type) and issubclass(val, ParamType):
@ -362,9 +375,7 @@ class MetaConfigNode(type):
for key,val in cls._init_dict.items():
# param descriptions
if isinstance(val, _Param):
cls._params[key] = val
# try to resolve local param types in local param_types scope
val.maybe_resolve_type(cls._param_types)
cls._new_param(key, val)
# init-time-only keywords
elif cls.init_keywords.has_key(key):
@ -387,99 +398,6 @@ class MetaConfigNode(type):
else:
setattr(cls, key, val)
def _isvalue(cls, name):
for c in cls._bases:
if c._params.has_key(name):
return True
for c in cls._bases:
if c._values.has_key(name):
return True
return False
# generator that iterates across all parameters for this class and
# all classes it inherits from
def _getparams(cls):
params = {}
for c in cls._bases:
for p,v in c._params.iteritems():
if not params.has_key(p):
params[p] = v
return params
# Lookup a parameter description by name in the given class.
def _getparam(cls, name, default = AttributeError):
for c in cls._bases:
if c._params.has_key(name):
return c._params[name]
if isSubClass(default, Exception):
raise default, \
"object '%s' has no attribute '%s'" % (cls.__name__, name)
else:
return default
def _hasvalue(cls, name):
for c in cls._bases:
if c._values.has_key(name):
return True
return False
def _getvalues(cls):
values = {}
for i,c in enumerate(cls._bases):
for p,v in c._values.iteritems():
if not values.has_key(p):
values[p] = v
for p,v in c._params.iteritems():
if not values.has_key(p) and hasattr(v, 'default'):
try:
v.valid(v.default)
except TypeError:
panic("Invalid default %s for param %s in node %s"
% (v.default,p,cls.__name__))
v = v.default
cls._setvalue(p, v)
values[p] = v
return values
def _getvalue(cls, name, default = AttributeError):
value = None
for c in cls._bases:
if c._values.has_key(name):
value = c._values[name]
break
if value is not None:
return value
param = cls._getparam(name, None)
if param is not None and hasattr(param, 'default'):
param.valid(param.default)
value = param.default
cls._setvalue(name, value)
return value
if isSubClass(default, Exception):
raise default, 'value for %s not found' % name
else:
return default
def _setvalue(cls, name, value):
cls._values[name] = value
def __getattr__(cls, attr):
if cls._isvalue(attr):
return Value(cls, attr)
if attr == '_cpp_param_decl' and hasattr(cls, 'type'):
return cls.type + '*'
raise AttributeError, \
"object '%s' has no attribute '%s'" % (cls.__name__, attr)
def _set_keyword(cls, keyword, val, kwtype):
if not isinstance(val, kwtype):
raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \
@ -488,6 +406,13 @@ class MetaConfigNode(type):
val = classmethod(val)
type.__setattr__(cls, keyword, val)
def _new_param(cls, name, value):
cls._params[name] = value
if hasattr(value, 'default'):
cls._values[name] = value.default
# try to resolve local param types in local param_types scope
value.maybe_resolve_type(cls._param_types)
# Set attribute (called on foo.attr = value when foo is an
# instance of class cls).
def __setattr__(cls, attr, value):
@ -501,23 +426,33 @@ class MetaConfigNode(type):
return
# must be SimObject param
param = cls._getparam(attr, None)
param = cls._params.get(attr, None)
if param:
# It's ok: set attribute by delegating to 'object' class.
# Note the use of param.make_value() to verify/canonicalize
# the assigned value
try:
param.valid(value)
except:
panic("Error setting param %s.%s to %s\n" % \
(cls.__name__, attr, value))
cls._setvalue(attr, value)
except Exception, e:
panic("Exception: %s\nError setting param %s.%s to %s\n" % \
(e, cls.__name__, attr, value))
cls._values[attr] = value
elif isConfigNode(value) or isSimObjSequence(value):
cls._setvalue(attr, value)
cls._values[attr] = value
else:
raise AttributeError, \
"Class %s has no parameter %s" % (cls.__name__, attr)
def __getattr__(cls, attr):
if cls._params.has_key(attr) or cls._values.has_key(attr):
return Value(cls, attr)
if attr == '_cpp_param_decl' and hasattr(cls, 'type'):
return cls.type + '*'
raise AttributeError, \
"object '%s' has no attribute '%s'" % (cls.__name__, attr)
def add_child(cls, instance, name, child):
if isNullPointer(child) or instance.top_child_names.has_key(name):
return
@ -547,7 +482,7 @@ class MetaConfigNode(type):
if hasattr(cls, 'check'):
cls.check()
for key,value in cls._getvalues().iteritems():
for key,value in cls._values.iteritems():
if isConfigNode(value):
cls.add_child(instance, key, value)
if isinstance(value, (list, tuple)):
@ -555,11 +490,10 @@ class MetaConfigNode(type):
if len(vals):
cls.add_child(instance, key, vals)
for pname,param in cls._getparams().iteritems():
try:
value = cls._getvalue(pname)
except:
panic('Error getting %s' % pname)
for pname,param in cls._params.iteritems():
value = cls._values.get(pname, None)
if value is None:
panic('Error getting %s from %s' % (pname, name))
try:
if isConfigNode(value):
@ -618,7 +552,7 @@ class ConfigNode(object):
cls._anon_subclass_counter += 1
return cls.__metaclass__(name, (cls, ), kwargs)
class ParamContext(ConfigNode):
class ParamContext(ConfigNode,ParamType):
pass
class MetaSimObject(MetaConfigNode):
@ -879,7 +813,7 @@ class Value(object):
super(Value, self).__setattr__('obj', obj)
def _getattr(self):
return self.obj._getvalue(self.attr)
return self.obj._values.get(self.attr)
def __setattr__(self, attr, value):
setattr(self._getattr(), attr, value)

158
python/m5/multidict.py Normal file
View file

@ -0,0 +1,158 @@
__all__ = [ 'multidict' ]
class multidict(object):
__nodefault = object()
def __init__(self, parent = {}, **kwargs):
self.dict = dict(**kwargs)
self.parent = parent
self.deleted = {}
def __str__(self):
return str(dict(self.items()))
def __repr__(self):
return `dict(self.items())`
def __contains__(self, key):
return self.dict.has_key(key) or self.parent.has_key(key)
def __delitem__(self, key):
try:
del self.dict[key]
except KeyError, e:
if key in self.parent:
self.deleted[key] = True
else:
raise KeyError, e
def __setitem__(self, key, value):
self.deleted.pop(key, False)
self.dict[key] = value
def __getitem__(self, key):
try:
return self.dict[key]
except KeyError, e:
if not self.deleted.get(key, False) and key in self.parent:
return self.parent[key]
else:
raise KeyError, e
def __len__(self):
return len(self.dict) + len(self.parent)
def next(self):
for key,value in self.dict.items():
yield key,value
if self.parent:
for key,value in self.parent.next():
if key not in self.dict and key not in self.deleted:
yield key,value
def has_key(self, key):
return key in self
def iteritems(self):
for item in self.next():
yield item
def items(self):
return [ item for item in self.next() ]
def iterkeys(self):
for key,value in self.next():
yield key
def keys(self):
return [ key for key,value in self.next() ]
def itervalues(self):
for key,value in self.next():
yield value
def values(self):
return [ value for key,value in self.next() ]
def get(self, key, default=__nodefault):
try:
return self[key]
except KeyError, e:
if default != self.__nodefault:
return default
else:
raise KeyError, e
def setdefault(self, key, default):
try:
return self[key]
except KeyError:
self.deleted.pop(key, False)
self.dict[key] = default
return default
def _dump(self):
print 'multidict dump'
node = self
while isinstance(node, multidict):
print ' ', node.dict
node = node.parent
def _dumpkey(self, key):
values = []
node = self
while isinstance(node, multidict):
if key in node.dict:
values.append(node.dict[key])
node = node.parent
print key, values
if __name__ == '__main__':
test1 = multidict()
test2 = multidict(test1)
test3 = multidict(test2)
test4 = multidict(test3)
test1['a'] = 'test1_a'
test1['b'] = 'test1_b'
test1['c'] = 'test1_c'
test1['d'] = 'test1_d'
test1['e'] = 'test1_e'
test2['a'] = 'test2_a'
del test2['b']
test2['c'] = 'test2_c'
del test1['a']
test2.setdefault('f', multidict)
print 'test1>', test1.items()
print 'test2>', test2.items()
#print test1['a']
print test1['b']
print test1['c']
print test1['d']
print test1['e']
print test2['a']
#print test2['b']
print test2['c']
print test2['d']
print test2['e']
for key in test2.iterkeys():
print key
test2.get('g', 'foo')
#test2.get('b')
test2.get('b', 'bar')
test2.setdefault('b', 'blah')
print test1
print test2
print `test2`
print len(test2)
test3['a'] = [ 0, 1, 2, 3 ]
print test4