-# Copyright (c) 2017 ARM Limited
+# Copyright (c) 2017-2020 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# 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: Steve Reinhardt
-# Nathan Binkert
-# Andreas Hansson
-# Andreas Sandberg
from __future__ import print_function
+from __future__ import absolute_import
+from six import add_metaclass
+import six
+if six.PY3:
+ long = int
import sys
from types import FunctionType, MethodType, ModuleType
code('#include "base/str.hh"')
code('#include "cxx_config/${name}.hh"')
- if simobj._ports.values() != []:
- code('#include "mem/mem_object.hh"')
- code('#include "mem/port.hh"')
-
code()
code('${member_prefix}DirectoryEntry::DirectoryEntry()');
code('{')
for port in simobj._ports.values():
is_vector = isinstance(port, m5.params.VectorPort)
- is_master = port.role == 'MASTER'
+ is_requestor = port.role == 'GEM5 REQUESTOR'
code('ports["%s"] = new PortDesc("%s", %s, %s);' %
(port.name, port.name, cxx_bool(is_vector),
- cxx_bool(is_master)))
+ cxx_bool(is_requestor)))
code.dedent()
code('}')
'cxx_extra_bases' : list,
'cxx_exports' : list,
'cxx_param_exports' : list,
+ 'cxx_template_params' : list,
}
# Attributes that can be set any time
keywords = { 'check' : FunctionType }
value_dict['cxx_exports'] += cxx_exports
if 'cxx_param_exports' not in value_dict:
value_dict['cxx_param_exports'] = []
+ if 'cxx_template_params' not in value_dict:
+ value_dict['cxx_template_params'] = []
cls_dict['_value_dict'] = value_dict
cls = super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict)
if 'type' in value_dict:
cls._params = multidict() # param descriptions
cls._ports = multidict() # port descriptions
+ # Parameter names that are deprecated. Dict[str, DeprecatedParam]
+ # The key is the "old_name" so that when the old_name is used in
+ # python config files, we will use the DeprecatedParam object to
+ # translate to the new type.
+ cls._deprecated_params = multidict()
+
# class or instance attributes
cls._values = multidict() # param values
cls._hr_values = multidict() # human readable param values
if isinstance(c, MetaSimObject):
bTotal += 1
if bTotal > 1:
- raise TypeError, \
- "SimObjects do not support multiple inheritance"
+ raise TypeError(
+ "SimObjects do not support multiple inheritance")
base = bases[0]
cls._base = base
cls._params.parent = base._params
cls._ports.parent = base._ports
+ cls._deprecated_params.parent = base._deprecated_params
cls._values.parent = base._values
cls._hr_values.parent = base._hr_values
cls._children.parent = base._children
elif isinstance(val, Port):
cls._new_port(key, val)
+ # Deprecated variable names
+ elif isinstance(val, DeprecatedParam):
+ new_name, new_val = cls._get_param_by_value(val.newParam)
+ # Note: We don't know the (string) name of this variable until
+ # here, so now we can finish setting up the dep_param.
+ val.oldName = key
+ val.newName = new_name
+ cls._deprecated_params[key] = val
+
# init-time-only keywords
- elif cls.init_keywords.has_key(key):
+ elif key in cls.init_keywords:
cls._set_keyword(key, val, cls.init_keywords[key])
# default: use normal path (ends up in __setattr__)
def _set_keyword(cls, keyword, val, kwtype):
if not isinstance(val, kwtype):
- raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \
- (keyword, type(val), kwtype)
+ raise TypeError('keyword %s has bad type %s (expecting %s)' % \
+ (keyword, type(val), kwtype))
if isinstance(val, FunctionType):
val = classmethod(val)
type.__setattr__(cls, keyword, val)
try:
hr_value = value
value = param.convert(value)
- except Exception, e:
+ except Exception as e:
msg = "%s\nError setting param %s.%s to %s\n" % \
(e, cls.__name__, name, value)
e.args = (msg, )
cls._port_refs[attr] = ref
return ref
+ def _get_param_by_value(cls, value):
+ """Given an object, value, return the name and the value from the
+ internal list of parameter values. If this value can't be found, raise
+ a runtime error. This will search both the current object and its
+ parents.
+ """
+ for k,v in cls._value_dict.items():
+ if v == value:
+ return k,v
+ raise RuntimeError("Cannot find parameter {} in parameter list"
+ .format(value))
+
# Set attribute (called on foo.attr = value when foo is an
# instance of class cls).
def __setattr__(cls, attr, value):
type.__setattr__(cls, attr, value)
return
- if cls.keywords.has_key(attr):
+ if attr in cls.keywords:
cls._set_keyword(attr, value, cls.keywords[attr])
return
- if cls._ports.has_key(attr):
+ if attr in cls._ports:
cls._cls_get_port_ref(attr).connect(value)
return
if isSimObjectOrSequence(value) and cls._instantiated:
- raise RuntimeError, \
+ raise RuntimeError(
"cannot set SimObject parameter '%s' after\n" \
" class %s has been instantiated or subclassed" \
- % (attr, cls.__name__)
+ % (attr, cls.__name__))
# check for param
param = cls._params.get(attr)
return
# no valid assignment... raise exception
- raise AttributeError, \
- "Class %s has no parameter \'%s\'" % (cls.__name__, attr)
+ raise AttributeError(
+ "Class %s has no parameter \'%s\'" % (cls.__name__, attr))
def __getattr__(cls, attr):
if attr == 'cxx_class_path':
if attr == 'cxx_namespaces':
return cls.cxx_class_path[:-1]
- if cls._values.has_key(attr):
+ if attr == 'pybind_class':
+ return '_COLONS_'.join(cls.cxx_class_path)
+
+ if attr in cls._values:
return cls._values[attr]
- if cls._children.has_key(attr):
+ if attr in cls._children:
return cls._children[attr]
- raise AttributeError, \
- "object '%s' has no attribute '%s'" % (cls.__name__, attr)
+ try:
+ return getattr(cls.getCCClass(), attr)
+ except AttributeError:
+ raise AttributeError(
+ "object '%s' has no attribute '%s'" % (cls.__name__, attr))
def __str__(cls):
return cls.__name__
+ def getCCClass(cls):
+ return getattr(m5.internal.params, cls.pybind_class)
+
# See ParamValue.cxx_predecls for description.
def cxx_predecls(cls, code):
code('#include "params/$cls.hh"')
code('#include "${{cls.cxx_header}}"')
def pybind_decl(cls, code):
- class_path = cls.cxx_class.split('::')
- namespaces, classname = class_path[:-1], class_path[-1]
- py_class_name = '_COLONS_'.join(class_path) if namespaces else \
- classname;
+ py_class_name = cls.pybind_class
# The 'local' attribute restricts us to the params declared in
# the object itself, not including inherited params (which
# will also be inherited from the base class's param struct
# here). Sort the params based on their key
- params = map(lambda (k, v): v, sorted(cls._params.local.items()))
+ params = list(map(lambda k_v: k_v[1], sorted(cls._params.local.items())))
ports = cls._ports.local
code('''#include "pybind11/pybind11.h"
for k, v in sorted(cls._params.local.items())
] + [
PyBindProperty("port_%s_connection_count" % port.name)
- for port in ports.itervalues()
+ for port in ports.values()
]
for exp in param_exports:
exp.export(code, "%sParams" % cls)
code('static EmbeddedPyBind embed_obj("${0}", module_init, "${1}");',
cls, cls._base.type if cls._base else "")
+ _warned_about_nested_templates = False
# Generate the C++ declaration (.hh file) for this SimObject's
# param struct. Called from src/SConscript.
# the object itself, not including inherited params (which
# will also be inherited from the base class's param struct
# here). Sort the params based on their key
- params = map(lambda (k, v): v, sorted(cls._params.local.items()))
+ params = list(map(lambda k_v: k_v[1], sorted(cls._params.local.items())))
ports = cls._ports.local
try:
ptypes = [p.ptype for p in params]
print(params)
raise
- class_path = cls._value_dict['cxx_class'].split('::')
+ class CxxClass(object):
+ def __init__(self, sig, template_params=[]):
+ # Split the signature into its constituent parts. This could
+ # potentially be done with regular expressions, but
+ # it's simple enough to pick appart a class signature
+ # manually.
+ parts = sig.split('<', 1)
+ base = parts[0]
+ t_args = []
+ if len(parts) > 1:
+ # The signature had template arguments.
+ text = parts[1].rstrip(' \t\n>')
+ arg = ''
+ # Keep track of nesting to avoid splitting on ","s embedded
+ # in the arguments themselves.
+ depth = 0
+ for c in text:
+ if c == '<':
+ depth = depth + 1
+ if depth > 0 and not \
+ self._warned_about_nested_templates:
+ self._warned_about_nested_templates = True
+ print('Nested template argument in cxx_class.'
+ ' This feature is largely untested and '
+ ' may not work.')
+ elif c == '>':
+ depth = depth - 1
+ elif c == ',' and depth == 0:
+ t_args.append(arg.strip())
+ arg = ''
+ else:
+ arg = arg + c
+ if arg:
+ t_args.append(arg.strip())
+ # Split the non-template part on :: boundaries.
+ class_path = base.split('::')
+
+ # The namespaces are everything except the last part of the
+ # class path.
+ self.namespaces = class_path[:-1]
+ # And the class name is the last part.
+ self.name = class_path[-1]
+
+ self.template_params = template_params
+ self.template_arguments = []
+ # Iterate through the template arguments and their values. This
+ # will likely break if parameter packs are used.
+ for arg, param in zip(t_args, template_params):
+ type_keys = ('class', 'typename')
+ # If a parameter is a type, parse it recursively. Otherwise
+ # assume it's a constant, and store it verbatim.
+ if any(param.strip().startswith(kw) for kw in type_keys):
+ self.template_arguments.append(CxxClass(arg))
+ else:
+ self.template_arguments.append(arg)
+
+ def declare(self, code):
+ # First declare any template argument types.
+ for arg in self.template_arguments:
+ if isinstance(arg, CxxClass):
+ arg.declare(code)
+ # Re-open the target namespace.
+ for ns in self.namespaces:
+ code('namespace $ns {')
+ # If this is a class template...
+ if self.template_params:
+ code('template <${{", ".join(self.template_params)}}>')
+ # The actual class declaration.
+ code('class ${{self.name}};')
+ # Close the target namespaces.
+ for ns in reversed(self.namespaces):
+ code('} // namespace $ns')
code('''\
#ifndef __PARAMS__${cls}__
if cls == SimObject:
code('''#include <string>''')
+ cxx_class = CxxClass(cls._value_dict['cxx_class'],
+ cls._value_dict['cxx_template_params'])
+
# A forward class declaration is sufficient since we are just
# declaring a pointer.
- for ns in class_path[:-1]:
- code('namespace $ns {')
- code('class $0;', class_path[-1])
- for ns in reversed(class_path[:-1]):
- code('} // namespace $ns')
- code()
+ cxx_class.declare(code)
for param in params:
param.cxx_predecls(code)
- for port in ports.itervalues():
+ for port in ports.values():
port.cxx_predecls(code)
code()
for param in params:
param.cxx_decl(code)
- for port in ports.itervalues():
+ for port in ports.values():
port.cxx_decl(code)
code.dedent()
"""Decorator to export C++ functions to Python"""
def decorate(func):
- name = func.func_name
+ name = func.__name__
override = kwargs.get("override", False)
cxx_name = kwargs.get("cxx_name", name)
+ return_value_policy = kwargs.get("return_value_policy", None)
+ static = kwargs.get("static", False)
args, varargs, keywords, defaults = inspect.getargspec(func)
if varargs or keywords:
# Create tuples of (argument, default)
if defaults:
- args = args[:-len(defaults)] + zip(args[-len(defaults):], defaults)
+ args = args[:-len(defaults)] + \
+ list(zip(args[-len(defaults):], defaults))
# Don't include self in the argument list to PyBind
args = args[1:]
@wraps(func)
def cxx_call(self, *args, **kwargs):
- ccobj = self.getCCObject()
+ ccobj = self.getCCClass() if static else self.getCCObject()
return getattr(ccobj, name)(*args, **kwargs)
@wraps(func)
def py_call(self, *args, **kwargs):
- return self.func(*args, **kwargs)
+ return func(self, *args, **kwargs)
f = py_call if override else cxx_call
- f.__pybind = PyBindMethod(name, cxx_name=cxx_name, args=args)
+ f.__pybind = PyBindMethod(name, cxx_name=cxx_name, args=args,
+ return_value_policy=return_value_policy,
+ static=static)
return f
if not "created" in self.__dict__:
self.__dict__[name] = value
+class SimObjectCliWrapperException(Exception):
+ def __init__(self, message):
+ super(Exception, self).__init__(message)
+
+class SimObjectCliWrapper(object):
+ """
+ Wrapper class to restrict operations that may be done
+ from the command line on SimObjects.
+
+ Only parameters may be set, and only children may be accessed.
+
+ Slicing allows for multiple simultaneous assignment of items in
+ one statement.
+ """
+
+ def __init__(self, sim_objects):
+ self.__dict__['_sim_objects'] = list(sim_objects)
+
+ def __getattr__(self, key):
+ return SimObjectCliWrapper(sim_object._children[key]
+ for sim_object in self._sim_objects)
+
+ def __setattr__(self, key, val):
+ for sim_object in self._sim_objects:
+ if key in sim_object._params:
+ if sim_object._params[key].isCmdLineSettable():
+ setattr(sim_object, key, val)
+ else:
+ raise SimObjectCliWrapperException(
+ 'tried to set or unsettable' \
+ 'object parameter: ' + key)
+ else:
+ raise SimObjectCliWrapperException(
+ 'tried to set or access non-existent' \
+ 'object parameter: ' + key)
+
+ def __getitem__(self, idx):
+ """
+ Extends the list() semantics to also allow tuples,
+ for example object[1, 3] selects items 1 and 3.
+ """
+ out = []
+ if isinstance(idx, tuple):
+ for t in idx:
+ out.extend(self[t]._sim_objects)
+ else:
+ if isinstance(idx, int):
+ _range = range(idx, idx + 1)
+ elif not isinstance(idx, slice):
+ raise SimObjectCliWrapperException( \
+ 'invalid index type: ' + repr(idx))
+ for sim_object in self._sim_objects:
+ if isinstance(idx, slice):
+ _range = range(*idx.indices(len(sim_object)))
+ out.extend(sim_object[i] for i in _range)
+ return SimObjectCliWrapper(out)
+
+ def __iter__(self):
+ return iter(self._sim_objects)
+
# The SimObject class is the root of the special hierarchy. Most of
# the code in this class deals with the configuration hierarchy itself
# (parent/child node relationships).
+@add_metaclass(MetaSimObject)
class SimObject(object):
# Specify metaclass. Any class inheriting from SimObject will
# get this metaclass.
- __metaclass__ = MetaSimObject
type = 'SimObject'
abstract = True
cxx_header = "sim/sim_object.hh"
- cxx_extra_bases = [ "Drainable", "Serializable" ]
+ cxx_extra_bases = [ "Drainable", "Serializable", "Stats::Group" ]
eventq_index = Param.UInt32(Parent.eventq_index, "Event Queue Index")
cxx_exports = [
PyBindMethod("initState"),
PyBindMethod("memInvalidate"),
PyBindMethod("memWriteback"),
- PyBindMethod("regStats"),
- PyBindMethod("resetStats"),
PyBindMethod("regProbePoints"),
PyBindMethod("regProbeListeners"),
PyBindMethod("startup"),
# Do children before parameter values so that children that
# are also param values get cloned properly.
self._children = {}
- for key,val in ancestor._children.iteritems():
+ for key,val in ancestor._children.items():
self.add_child(key, val(_memo=memo_dict))
# Inherit parameter values from class using multidict so
self._values = multidict(ancestor._values)
self._hr_values = multidict(ancestor._hr_values)
# clone SimObject-valued parameters
- for key,val in ancestor._values.iteritems():
+ for key,val in ancestor._values.items():
val = tryAsSimObjectOrVector(val)
if val is not None:
self._values[key] = val(_memo=memo_dict)
# clone port references. no need to use a multidict here
# since we will be creating new references for all ports.
self._port_refs = {}
- for key,val in ancestor._port_refs.iteritems():
+ for key,val in ancestor._port_refs.items():
self._port_refs[key] = val.clone(self, memo_dict)
# apply attribute assignments from keyword args, if any
- for key,val in kwargs.iteritems():
+ for key,val in kwargs.items():
setattr(self, key, val)
# "Clone" the current instance by creating another instance of
# no memo_dict: must be top-level clone operation.
# this is only allowed at the root of a hierarchy
if self._parent:
- raise RuntimeError, "attempt to clone object %s " \
+ raise RuntimeError("attempt to clone object %s " \
"not at the root of a tree (parent = %s)" \
- % (self, self._parent)
+ % (self, self._parent))
# create a new dict and use that.
memo_dict = {}
kwargs['_memo'] = memo_dict
- elif memo_dict.has_key(self):
+ elif self in memo_dict:
# clone already done & memoized
return memo_dict[self]
return self.__class__(_ancestor = self, **kwargs)
return ref
def __getattr__(self, attr):
- if self._ports.has_key(attr):
+ if attr in self._deprecated_params:
+ dep_param = self._deprecated_params[attr]
+ dep_param.printWarning(self._name, self.__class__.__name__)
+ return getattr(self, self._deprecated_params[attr].newName)
+
+ if attr in self._ports:
return self._get_port_ref(attr)
- if self._values.has_key(attr):
+ if attr in self._values:
return self._values[attr]
- if self._children.has_key(attr):
+ if attr in self._children:
return self._children[attr]
# If the attribute exists on the C++ object, transparently
err_string += "\n (C++ object is not yet constructed," \
" so wrapped C++ methods are unavailable.)"
- raise AttributeError, err_string
+ raise AttributeError(err_string)
# Set attribute (called on foo.attr = value when foo is an
# instance of class cls).
object.__setattr__(self, attr, value)
return
- if self._ports.has_key(attr):
+ if attr in self._deprecated_params:
+ dep_param = self._deprecated_params[attr]
+ dep_param.printWarning(self._name, self.__class__.__name__)
+ return setattr(self, self._deprecated_params[attr].newName, value)
+
+ if attr in self._ports:
# set up port connection
self._get_port_ref(attr).connect(value)
return
try:
hr_value = value
value = param.convert(value)
- except Exception, e:
+ except Exception as e:
msg = "%s\nError setting param %s.%s to %s\n" % \
(e, self.__class__.__name__, attr, value)
e.args = (msg, )
return
# no valid assignment... raise exception
- raise AttributeError, "Class %s has no parameter %s" \
- % (self.__class__.__name__, attr)
+ raise AttributeError("Class %s has no parameter %s" \
+ % (self.__class__.__name__, attr))
# this hack allows tacking a '[0]' onto parameters that may or may
def __getitem__(self, key):
if key == 0:
return self
- raise IndexError, "Non-zero index '%s' to SimObject" % key
+ raise IndexError("Non-zero index '%s' to SimObject" % key)
# this hack allows us to iterate over a SimObject that may
# not be a vector, so we can call a loop over it and get just one
if child.has_parent():
warn("add_child('%s'): child '%s' already has parent", name,
child.get_name())
- if self._children.has_key(name):
+ if name in self._children:
# This code path had an undiscovered bug that would make it fail
# at runtime. It had been here for a long time and was only
# exposed by a buggy script. Changes here will probably not be
# that when we instantiate all the parameter objects we're still
# inside the configuration hierarchy.
def adoptOrphanParams(self):
- for key,val in self._values.iteritems():
+ for key,val in self._values.items():
if not isSimObjectVector(val) and isSimObjectSequence(val):
# need to convert raw SimObject sequences to
# SimObjectVector class so we can call has_parent()
return self._name
return ppath + "." + self._name
+ def path_list(self):
+ if self._parent:
+ return self._parent.path_list() + [ self._name, ]
+ else:
+ # Don't include the root node
+ return []
+
def __str__(self):
return self.path()
return self, True
found_obj = None
- for child in self._children.itervalues():
+ for child in self._children.values():
visited = False
if hasattr(child, '_visited'):
visited = getattr(child, '_visited')
if isinstance(child, ptype) and not visited:
if found_obj != None and child != found_obj:
- raise AttributeError, \
+ raise AttributeError(
'parent.any matched more than one: %s %s' % \
- (found_obj.path, child.path)
+ (found_obj.path, child.path))
found_obj = child
# search param space
- for pname,pdesc in self._params.iteritems():
+ for pname,pdesc in self._params.items():
if issubclass(pdesc.ptype, ptype):
match_obj = self._values[pname]
if found_obj != None and found_obj != match_obj:
- raise AttributeError, \
+ raise AttributeError(
'parent.any matched more than one: %s and %s' % \
- (found_obj.path, match_obj.path)
+ (found_obj.path, match_obj.path))
found_obj = match_obj
return found_obj, found_obj != None
def find_all(self, ptype):
all = {}
# search children
- for child in self._children.itervalues():
+ for child in self._children.values():
# a child could be a list, so ensure we visit each item
if isinstance(child, list):
children = child
child_all, done = child.find_all(ptype)
all.update(dict(zip(child_all, [done] * len(child_all))))
# search param space
- for pname,pdesc in self._params.iteritems():
+ for pname,pdesc in self._params.items():
if issubclass(pdesc.ptype, ptype):
match_obj = self._values[pname]
if not isproxy(match_obj) and not isNullPointer(match_obj):
return self
def unproxyParams(self):
- for param in self._params.iterkeys():
+ for param in self._params.keys():
value = self._values.get(param)
if value != None and isproxy(value):
try:
# Unproxy ports in sorted order so that 'append' operations on
# vector ports are done in a deterministic fashion.
- port_names = self._ports.keys()
+ port_names = list(self._ports.keys())
port_names.sort()
for port_name in port_names:
port = self._port_refs.get(port_name)
cc_params = cc_params_struct()
cc_params.name = str(self)
- param_names = self._params.keys()
+ param_names = list(self._params.keys())
param_names.sort()
for param in param_names:
value = self._values.get(param)
else:
setattr(cc_params, param, value)
- port_names = self._ports.keys()
+ port_names = list(self._ports.keys())
port_names.sort()
for port_name in port_names:
port = self._port_refs.get(port_name, None)
if not self._ccObject:
# Make sure this object is in the configuration hierarchy
if not self._parent and not isRoot(self):
- raise RuntimeError, "Attempt to instantiate orphan node"
+ raise RuntimeError("Attempt to instantiate orphan node")
# Cycles in the configuration hierarchy are not supported. This
# will catch the resulting recursion and stop.
self._ccObject = -1
params = self.getCCParams()
self._ccObject = params.create()
elif self._ccObject == -1:
- raise RuntimeError, "%s: Cycle found in configuration hierarchy." \
- % self.path()
+ raise RuntimeError("%s: Cycle found in configuration hierarchy." \
+ % self.path())
return self._ccObject
def descendants(self):
# The order of the dict is implementation dependent, so sort
# it based on the key (name) to ensure the order is the same
# on all hosts
- for (name, child) in sorted(self._children.iteritems()):
+ for (name, child) in sorted(self._children.items()):
for obj in child.descendants():
yield obj
def getValue(self):
return self.getCCObject()
+ @cxxMethod(return_value_policy="reference")
+ def getPort(self, if_name, idx):
+ pass
+
# Create C++ port connections corresponding to the connections in
# _port_refs
def connectPorts(self):
# Sort the ports based on their attribute name to ensure the
# order is the same on all hosts
- for (attr, portRef) in sorted(self._port_refs.iteritems()):
+ for (attr, portRef) in sorted(self._port_refs.items()):
portRef.ccConnect()
# Default function for generating the device structure.
yield # make this function a (null) generator
def recurseDeviceTree(self, state):
- for child in self._children.itervalues():
+ for child in self._children.values():
for item in child: # For looping over SimObjectVectors
for dt in item.generateDeviceTree(state):
yield dt
+ # On a separate method otherwise certain buggy Python versions
+ # would fail with: SyntaxError: unqualified exec is not allowed
+ # in function 'apply_config'
+ def _apply_config_get_dict(self):
+ return {
+ child_name: SimObjectCliWrapper(
+ iter(self._children[child_name]))
+ for child_name in self._children
+ }
+
+ def apply_config(self, params):
+ """
+ exec a list of Python code strings contained in params.
+
+ The only exposed globals to those strings are the child
+ SimObjects of this node.
+
+ This function is intended to allow users to modify SimObject
+ parameters from the command line with Python statements.
+ """
+ d = self._apply_config_get_dict()
+ for param in params:
+ exec(param, d)
+
+ def get_simobj(self, simobj_path):
+ """
+ Get all sim objects that match a given string.
+
+ The format is the same as that supported by SimObjectCliWrapper.
+
+ :param simobj_path: Current state to be in.
+ :type simobj_path: str
+ """
+ d = self._apply_config_get_dict()
+ return eval(simobj_path, d)
+
# Function to provide to C++ so it can look up instances based on paths
def resolveSimObject(name):
obj = instanceDict[name]
def coerceSimObjectOrVector(value):
value = tryAsSimObjectOrVector(value)
if value is None:
- raise TypeError, "SimObject or SimObjectVector expected"
+ raise TypeError("SimObject or SimObjectVector expected")
return value
baseClasses = allClasses.copy()