def insert_subnode(self, namespace, subnode): """Insert a subnode into this component :param subnode: An object of type ``DynamicsClass``. :param namespace: A `string` specifying the name of the component in this components namespace. :raises: ``NineMLRuntimeException`` if there is already a subcomponent at the same namespace location .. note:: This method will clone the subnode. """ if not isinstance(namespace, basestring): err = 'Invalid namespace: %s' % type(subnode) raise NineMLRuntimeError(err) if not isinstance(subnode, DynamicsClass): err = 'Attempting to insert invalid ' err += 'object as subcomponent: %s' % type(subnode) raise NineMLRuntimeError(err) if namespace in self.subnodes: err = 'Key already exists in namespace: %s' % namespace raise NineMLRuntimeError(err) self.subnodes[namespace] = DynamicsClonerVisitor().visit(subnode) self.subnodes[namespace].set_parent_model(self) self._validate_self()
def __init__(self, filename): cls = TestableComponent # If we recieve a filename like 'iaf', that doesn't # end in '.py', then lets prepend the component directory # and append .py if not filename.endswith('.py'): compdir = LocationMgr.getComponentDir() filename = os.path.join(compdir, '%s.py' % filename) self.filename = filename self.mod = load_py_module(filename) # Get the component functor: if cls.functor_name not in self.mod.__dict__.keys(): err = """Can't load TestableComponnet from %s""" % self.filename err += """Can't find required method: %s""" % cls.functor_name raise NineMLRuntimeError(err) self.component_functor = self.mod.__dict__[cls.functor_name] # Check the functor will actually return us an object: try: c = self.component_functor() except Exception: raise NineMLRuntimeError('component_functor() threw an exception') if not isinstance(c, DynamicsClass): raise NineMLRuntimeError('Functor does not return Component Class') # Try and get the meta-data self.metadata = None if cls.metadata_name in self.mod.__dict__.keys(): self.metadata = self.mod.__dict__[cls.metadata_name]
def set_flattener(self, flattener): """Specifies the flattening object used to create this component, if this component was flattened from a hierarchical component""" if not flattener: raise NineMLRuntimeError('Setting flattener to None??') if self.flattener: raise NineMLRuntimeError('Trying to change flattener') self._flattener = flattener
def standardize_units(self): """ Standardized the units into a single set (no duplicates). Used to avoid naming conflicts when writing to file. """ # Get the set of all units and dimensions that are used in the document # Note that Dimension & Unit objects are equal even if they have # different names so when this set is traversed the dimension/unit will # be substituted for the first equivalent dimension/unit. all_units = set(chain(*[o.all_units for o in self.itervalues()])) all_dimensions = set( chain([u.dimension for u in all_units], *[o.all_dimensions for o in self.itervalues()])) # Delete unused units from the document for k, o in self.items(): if ((isinstance(o, nineml.abstraction_layer.Unit) and o not in all_units) or (isinstance(o, nineml.abstraction_layer.Dimension) and o not in all_dimensions)): del self[k] # Add missing units and dimensions to the document for unit in all_units: if unit.name in self: if unit != self[unit.name]: raise NineMLRuntimeError( "Name of unit '{}' conflicts with existing object of " "differring value or type '{}' and '{}'".format( unit.name, unit, self[unit.name])) self[unit.name] = unit for dimension in all_dimensions: if dimension.name in self: if dimension != self[dimension.name]: raise NineMLRuntimeError( "Name of dimension '{}' conflicts with existing object" " of differring value or type '{}' and '{}'".format( dimension.name, dimension, self[unit.name])) self[dimension.name] = dimension # Replace units and dimensions with those in the superset for obj in self.itervalues(): for a in obj.attributes_with_dimension: try: std_dim = next(d for d in all_dimensions if d == a.dimension) except StopIteration: assert False, \ ("Did not find matching dimension in supposed superset" " of dimensions") a.set_dimension(std_dim) for a in obj.attributes_with_units: try: std_units = next(u for u in all_units if u == a.units) except StopIteration: assert False, \ ("Did not find matching unit in supposed superset" " of units") a.set_units(std_units)
def __init__(self, lhs, rhs): ExpressionWithLHS.__init__(self, rhs) if not MathUtil.is_single_symbol(lhs): err = 'Expecting a single symbol on the LHS; got: %s' % lhs raise NineMLRuntimeError(err) if not is_valid_lhs_target(lhs): err = 'Invalid LHS target: %s' % lhs raise NineMLRuntimeError(err) self._lhs = lhs.strip()
def add(self, element): try: if not isinstance(element, TopLevelObject): raise NineMLRuntimeError( "Could not add {} as it is not a document level NineML " "object ('{}') ".format(element.element_name, "', '".join(self.top_level_types))) except AttributeError: raise NineMLRuntimeError("Could not add {} as it is not a NineML " "object".format(element)) if element.name in self: raise NineMLRuntimeError( "Could not add element '{}' as an element with that name " "already exists in the document".format(element.name)) self[element.name] = element
def from_xml(cls, element, url=None): if element.tag != NINEML + cls.element_name: raise Exception("Not a NineML root ('{}')".format(element.tag)) # Initialise the document elements = {'_url': url} # Loop through child elements, determine the class needed to extract # them and add them to the dictionary annotations = None for child in element.getchildren(): if child.tag.startswith(NINEML): element_name = child.tag[len(NINEML):] if element_name == Annotations.element_name: assert annotations is None, \ "Multiple annotations tags found" annotations = Annotations.from_xml(child) continue try: child_cls = getattr(nineml.user_layer, element_name) except AttributeError: try: child_cls = getattr(nineml.abstraction_layer, element_name) except AttributeError: raise NineMLRuntimeError( "Did not find matching NineML class for '{}' " "element".format(element_name)) if not issubclass(child_cls, TopLevelObject): raise NineMLRuntimeError( "'{}' is not a valid top-level NineML element".format( element_name)) else: raise NotImplementedError( "Cannot load '{}' element (extensions not implemented)". format(child.tag)) # Units use 'symbol' as their unique identifier (from LEMS) all # other elements use 'name' name = child.attrib.get('name', child.attrib.get('symbol')) if name in elements: raise NineMLRuntimeError( "Duplicate identifier '{ob1}:{name}'in NineML file '{url}'" .format(name=name, ob1=elements[name].cls.element_name, ob2=child_cls.element_name, url=url or '')) elements[name] = cls._Unloaded(name, child, child_cls) document = cls(**elements) document.annotations = annotations return document
def __init__(self, name, dimension=None, reduce_op='+'): if reduce_op not in self._reduce_op_map.keys(): err = ("%s('%s')" + "specified undefined reduce_op: '%s'") %\ (self.__class__.__name__, name, str(reduce_op)) raise NineMLRuntimeError(err) super(AnalogReducePort, self).__init__(name, dimension) self._reduce_op = reduce_op
def action_componentclass(self, componentclass, namespace): unresolved_aliases = dict((a.lhs, a) for a in componentclass.aliases) def alias_contains_unresolved_symbols(alias): unresolved = [sym for sym in alias.rhs_atoms if sym in unresolved_aliases] return len(unresolved) != 0 def get_resolved_aliases(): return [alias for alias in unresolved_aliases.values() if not alias_contains_unresolved_symbols(alias)] while(unresolved_aliases): resolved_aliases = get_resolved_aliases() if resolved_aliases: for r in resolved_aliases: del unresolved_aliases[r.lhs] else: errmsg = "Unable to resolve all aliases in %s. " % namespace errmsg += "You may have a recursion issue." errmsg += ("Remaining Aliases: %s" % ','.join(unresolved_aliases.keys())) raise NineMLRuntimeError(errmsg)
def __init__(self, componentclass): PerNamespaceDynamicsValidator.__init__( self, require_explicit_overrides=False) self.connected_regimes_from_regime = defaultdict(set) self.regimes_in_namespace = defaultdict(set) self.visit(componentclass) def add_connected_regimes_recursive(regime, connected): connected.add(regime) for r in self.connected_regimes_from_regime[regime]: if r not in connected: add_connected_regimes_recursive(r, connected) for namespace, regimes in self.regimes_in_namespace.iteritems(): # Perhaps we have no transition graph; this is OK: if len(regimes) == 0: continue connected = set() add_connected_regimes_recursive(regimes[0], connected) if len(connected) != len(self.regimes_in_namespace[namespace]): raise NineMLRuntimeError('Transition graph is contains ' 'islands')
def from_str(cls, alias_string): """Creates an Alias object from a string""" if not cls.is_alias_str(alias_string): errmsg = "Invalid Alias: %s" % alias_string raise NineMLRuntimeError(errmsg) lhs, rhs = alias_string.split(':=') return Alias(lhs=lhs.strip(), rhs=rhs.strip())
def get_new_regime(self, old_regime_string): """ for example: old_regime_string = ('iaf:subthresholdregime ' 'cobaInhib:cobadefaultregime ' 'cobaExcit:cobadefaultregime') """ # Lets create a dictionary that maps 'NamespaceAddress' to regime name # from the input string: # old_regime_string = 'iaf:subthresholdregime' # 'cobaInhib:cobadefaultregime' # 'cobaExcit:cobadefaultregime' nsstr_regimename = [l.split(':') for l in old_regime_string.split()] ns_regimename = dict([(NamespaceAddress(ns), regime_name) for (ns, regime_name) in nsstr_regimename]) # OK, now lets go through our old componentswithregimes, # and find the regime that was specified. target_regime_tuple = [] for c in self.componentswithregimes: comp_ns = c.get_node_addr() if comp_ns not in ns_regimename: err = ('Looking for a regime in namespace: {}, but not found.' .format(comp_ns)) err += ('\nNamespaces: {}' .format(','.join([str(ns) for ns in ns_regimename.keys()]))) err += '\nSpecified String: {}'.format(old_regime_string) raise NineMLRuntimeError(err) target_regime_name = ns_regimename[comp_ns] regime_map = dict([(r.name, r) for r in c.regimes]) if target_regime_name not in regime_map: err = 'Namespace has no regime named: %s' err += '\nRegimes: %s' % (str(regime_map.keys())) raise NineMLRuntimeError(err) target_regime_tuple.append(regime_map[target_regime_name]) target_regime_tuple = tuple(target_regime_tuple) new_regime = self.old_regime_tuple_to_new_regime_map[ target_regime_tuple] return new_regime
def get_local_name(self): """ Returns the local reference; i.e. the last field in the address, as a ``string`` """ if self.is_root_namespace(): err = "Can't call get_local_name() on root namespace" raise NineMLRuntimeError(err) return self.loctuple[-1]
def rename_port(cls, componentclass, old_port_name, new_port_name): """ Renames a port in a componentclass """ if not componentclass.is_flat(): raise NineMLRuntimeError('rename_port() on non-flat ' 'componentclass') # Find the old port: port = filter_expect_single(componentclass.analog_ports, lambda ap: ap.name == old_port_name) port._name = new_port_name
def __init__(self, componentclass): PerNamespaceComponentValidator.__init__( self, require_explicit_overrides=False) self.available_symbols = defaultdict(list) self.aliases = defaultdict(list) self.time_derivatives = defaultdict(list) self.state_assignments = defaultdict(list) self.visit(componentclass) excludes = get_reserved_and_builtin_symbols() # Check Aliases: for ns, aliases in self.aliases.iteritems(): for alias in aliases: for rhs_atom in alias.rhs_atoms: if rhs_atom in excludes: continue if rhs_atom not in self.available_symbols[ns]: err = ('Unresolved Symbol in Alias: %s [%s]' % (rhs_atom, alias)) raise NineMLRuntimeError(err) # Check TimeDerivatives: for ns, timederivatives in self.time_derivatives.iteritems(): for timederivative in timederivatives: for rhs_atom in timederivative.rhs_atoms: if (rhs_atom not in self.available_symbols[ns] and rhs_atom not in excludes): err = ('Unresolved Symbol in Time Derivative: %s [%s]' % (rhs_atom, timederivative)) raise NineMLRuntimeError(err) # Check StateAssignments for ns, state_assignments in self.state_assignments.iteritems(): for state_assignment in state_assignments: for rhs_atom in state_assignment.rhs_atoms: if (rhs_atom not in self.available_symbols[ns] and rhs_atom not in excludes): err = ('Unresolved Symbol in Assignment: %s [%s]' % (rhs_atom, state_assignment)) raise NineMLRuntimeError(err)
def check_conflicting_dimension(self, dimension): try: if dimension != self.dimensions[dimension.name]: err = ("Duplication of dimension name '{}' for differing " "dimensions ('{}', '{}')".format( dimension.name, dimension, self.dimensions[dimension.name])) raise NineMLRuntimeError(err) except KeyError: self.dimensions[dimension.name] = dimension
def resolve_transitions(self): while self.unresolved_transitions: transition, regime_index = self.unresolved_transitions.pop() if regime_index in self.changed_regime_indices: raise NineMLRuntimeError( 'Something has gone wrong with event resolution. ' 'Changing Regime Twice!') self.changed_regime_indices.add(regime_index) self.resolve_transition(transition, regime_index)
def remap_port_to_parameter(cls, componentclass, port_name): """ Renames a port in a componentclass """ if not componentclass.is_flat(): raise NineMLRuntimeError('rename_port_to_parameter() on non-flat ' 'componentclass') # Find the old port: port = filter_expect_single(componentclass.analog_ports, lambda ap: ap.name == port_name) componentclass._analog_ports.remove(port) # Add a new parameter: componentclass._parameters[port_name] = Parameter(port_name)
def __init__(self, componentclass): PerNamespaceDynamicsValidator.__init__( self, require_explicit_overrides=False) self.sv_declared = defaultdict(list) self.state_assignments_lhses = defaultdict(list) self.visit(componentclass) for namespace, state_assignments_lhs in self.state_assignments_lhses.\ iteritems(): for td in state_assignments_lhs: if td not in self.sv_declared[namespace]: err = 'Not Assigning to state-variable: {}'.format(td) raise NineMLRuntimeError(err)
def __init__(self, componentclass): PerNamespaceDynamicsValidator.__init__( self, require_explicit_overrides=False) self.sv_declared = defaultdict(list) self.time_derivatives_used = defaultdict(list) self.visit(componentclass) for namespace, time_derivatives in self.time_derivatives_used.\ iteritems(): for td in time_derivatives: if td not in self.sv_declared[namespace]: err = 'StateVariable not declared: %s' % td raise NineMLRuntimeError(err)
def close_all_reduce_ports(cls, componentclass, exclude=None): """ Closes all the ``reduce`` ports on a componentclass by assigning them a value of 0 """ if not componentclass.is_flat(): raise NineMLRuntimeError('close_all_reduce_ports() on non-flat ' 'componentclass') for arp in componentclass.query.analog_reduce_ports: if exclude and arp.name in exclude: continue cls.close_analog_port(componentclass=componentclass, port_name=arp.name, value='0')
def from_str(cls, time_derivative_string): """Creates an TimeDerivative object from a string""" # Note: \w = [a-zA-Z0-9_] tdre = re.compile(r"""\s* d(?P<dependent_var>[a-zA-Z][a-zA-Z0-9_]*)/dt \s* = \s* (?P<rhs> .*) """, re.VERBOSE) match = tdre.match(time_derivative_string) if not match: err = "Unable to load time derivative: %s" % time_derivative_string raise NineMLRuntimeError(err) dependent_variable = match.groupdict()['dependent_var'] rhs = match.groupdict()['rhs'] return TimeDerivative(dependent_variable=dependent_variable, rhs=rhs)
def __init__(self, name, document, url=None): """ docstring needed `name` -- a name of an existing componentclass to refer to `document` -- a Document object containing the top-level objects in the current file `url` -- a url of the file containing the exiting componentclass """ super(Reference, self).__init__(name, document, url) if not isinstance(self._referred_to, BaseULObject): msg = ("Reference points to a non-user-layer object '{}'".format( self._referred_to.name)) raise NineMLRuntimeError(msg) self._referred_to.from_reference = self
def _resolve_transition_regime_names(self): # Check that the names of the regimes are unique: names = [r.name for r in self.regimes] assert_no_duplicates(names) # Create a map of regime names to regimes: regime_map = dict([(r.name, r) for r in self.regimes]) # We only worry about 'target' regimes, since source regimes are taken # care of for us by the Regime objects they are attached to. for trans in self.transitions: if trans.target_regime_name not in regime_map: raise NineMLRuntimeError("Can't find regime '{}'".format( trans.target_regime_name)) trans.set_target_regime(regime_map[trans.target_regime_name])
def __init__(self, componentclass): super(OutputAnalogPortsDynamicsValidator, self).__init__(require_explicit_overrides=False) self.output_analogports = defaultdict(list) self.available_symbols = defaultdict(list) self.visit(componentclass) for namespace, analogports in self.output_analogports.iteritems(): for ap in analogports: if ap not in self.available_symbols[namespace]: raise NineMLRuntimeError( 'Unable to find an Alias or State variable for ' 'analog-port: %s' % ap)
def __init__(self, componentclass, old_symbol_name, new_symbol_name): ComponentActionVisitor.__init__( self, require_explicit_overrides=True) self.old_symbol_name = old_symbol_name self.new_symbol_name = new_symbol_name self.namemap = {old_symbol_name: new_symbol_name} if not componentclass.is_flat(): raise NineMLRuntimeError('Rename Symbol called on non-flat model') self.lhs_changes = [] self.rhs_changes = [] self.port_changes = [] self.visit(componentclass) componentclass._validate_self()
def get_parent_addr(self): """Return the address of an namespace higher >>> a = NamespaceAddress('level1.level2.level3') >>> a NameSpaceAddress: '/level1/level2/level3/' >>> a.get_parent_addr() NameSpaceAddress: '/level1/level2/' """ if self.is_root_namespace(): err = "Can't call get_parent_addr() on root namespace" raise NineMLRuntimeError(err) return NamespaceAddress(loc=tuple(self.loctuple[:-1]))
def _load_blocks(self, element, blocks): """ Creates a dictionary that maps class-types to instantiated objects """ # Initialise loaded objects with empty lists loaded_objects = dict((block, []) for block in blocks) for t in element.iterchildren(tag=etree.Element): # Strip namespace tag = t.tag[len(NINEML):] if t.tag.startswith(NINEML) else t.tag if tag not in blocks: err = "Unexpected block tag: %s " % tag err += '\n Expected: %s' % ','.join(blocks) raise NineMLRuntimeError(err) loaded_objects[tag].append(self._get_loader(tag)(self, t)) return loaded_objects
def add_on_condition(self, on_condition): """Add an |OnCondition| transition which leaves this regime If the on_condition object has not had its target regime name set in the constructor, or by calling its ``set_target_regime_name()``, then the target is assumed to be this regime, and will be set appropriately. The source regime for this transition will be set as this regime. """ if not isinstance(on_condition, OnCondition): err = ("Expected 'OnCondition' Obj, but got %s" % (type(on_condition))) raise NineMLRuntimeError(err) self._resolve_references_on_transition(on_condition) self._on_conditions.append(on_condition)
def load_py_module(filename): """Takes the fully qualified path of a python file, loads it and returns the module object """ if not os.path.exists(filename): print "CWD:", os.getcwd() raise NineMLRuntimeError('File does not exist %s' % filename) dirname, fname = os.path.split(filename) sys.path = [dirname] + sys.path module_name = fname.replace('.py', '') module_name_short = module_name module = __import__(module_name) return module