def test_check_list_contain_same_items(self): # Signature: name(lst1, lst2, desc1='', desc2='', ignore=[], desc='') # No Docstring from nineml.utility import check_list_contain_same_items from nineml.exceptions import NineMLRuntimeError self.assertRaises( NineMLRuntimeError, check_list_contain_same_items, [1, 2, 3, 4, 5], [1, 2, 3, 4], ) self.assertRaises( NineMLRuntimeError, check_list_contain_same_items, ['some', 'funny', 'order', 'in', 'extra'], ['some', 'funny', 'order', 'in'], ) # Good cases: check_list_contain_same_items( ['in', 'some', 'funny', 'order', ], ['some', 'funny', 'order', 'in'], ) check_list_contain_same_items( [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], ) check_list_contain_same_items( [1, 3, 4, 5, 2], [1, 2, 3, 4, 5], ) # Chack ignoring: check_list_contain_same_items( [1, 3, 4, 5, 2], [1, 2, 3, 4, 5, 6], ignore=[6], )
def __init__(self, name, parameters=None, analog_ports=None, event_ports=None, dynamics=None, subnodes=None, portconnections=None, regimes=None, aliases=None, state_variables=None): """Constructs a ComponentClass :param name: The name of the component. :param parameters: A list containing either |Parameter| objects or strings representing the parameter names. If ``None``, then the parameters are automatically inferred from the |Dynamics| block. :param analog_ports: A list of |AnalogPorts|, which will be the local |AnalogPorts| for this object. :param event_ports: A list of |EventPorts| objects, which will be the local event-ports for this object. If this is ``None``, then they will be automatically inferred from the dynamics block. :param dynamics: A |Dynamics| object, defining the local dynamics of the component. :param subnodes: A dictionary mapping namespace-names to sub-component. [Type: ``{string:|ComponentClass|, string:|ComponentClass|, string:|ComponentClass|}`` ] describing the namespace of subcomponents for this component. :param portconnections: A list of pairs, specifying the connections between the ports of the subcomponents in this component. These can be `(|NamespaceAddress|, |NamespaceAddress|)' or ``(string, string)``. :param interface: A shorthand way of specifying the **interface** for this component; |Parameters|, |AnalogPorts| and |EventPorts|. ``interface`` takes a list of these objects, and automatically resolves them by type into the correct types. Examples: >>> a = ComponentClass(name='MyComponent1') .. todo:: Point this towards and example of constructing ComponentClasses. This can't be here, because we also need to know about dynamics. For examples """ # We can specify in the componentclass, and they will get forwarded to # the dynamics class. We check that we do not specify half-and-half: if dynamics is not None: if regimes or aliases or state_variables: err = "Either specify a 'dynamics' parameter, or " err += "state_variables /regimes/aliases, but not both!" raise NineMLRuntimeError(err) else: # We should always create a dynamics object, even is it is empty: dynamics = dyn.Dynamics(regimes=regimes, aliases=aliases, state_variables=state_variables) # Turn any strings in the parameter list into Parameters: from nineml.utility import filter_discrete_types if parameters is not None: param_types = (basestring, Parameter) param_td = filter_discrete_types(parameters, param_types) params_from_strings = [Parameter(s) for s in param_td[basestring]] parameters = param_td[Parameter] + params_from_strings self._query = componentqueryer.ComponentQueryer(self) # EventPort, StateVariable and Parameter Inference: inferred_struct = InterfaceInferer(dynamics, analog_ports=analog_ports) inf_check = lambda l1, l2, desc: check_list_contain_same_items(l1, l2, desc1='Declared', desc2='Inferred', ignore=['t'], desc=desc) # Check any supplied parameters match: if parameters is not None: parameter_names = [p.name for p in parameters] inf_check(parameter_names, inferred_struct.parameter_names, 'Parameters') else: parameters = [Parameter(n) for n in inferred_struct.parameter_names] # Check any supplied state_variables match: if dynamics._state_variables: state_var_names = [p.name for p in dynamics.state_variables] inf_check(state_var_names, inferred_struct.state_variable_names, 'StateVariables') else: state_vars = [StateVariable(n) for n in inferred_struct.state_variable_names] dynamics._state_variables = state_vars # Check Event Ports Match: if event_ports is not None: ip_evt_names = [ep.name for ep in event_ports if ep.is_incoming()] op_evt_names = [ep.name for ep in event_ports if ep.is_outgoing()] # Check things Match: inf_check(ip_evt_names, inferred_struct.input_event_port_names, 'Event Ports In') inf_check(op_evt_names, inferred_struct.output_event_port_names, 'Event Ports Out') else: event_ports = [] # Event ports not supplied, so lets use the inferred ones. for evt_port_name in inferred_struct.input_event_port_names: event_ports.append(EventPort(name=evt_port_name, mode='recv')) for evt_port_name in inferred_struct.output_event_port_names: event_ports.append(EventPort(name=evt_port_name, mode='send')) # Construct super-classes: ComponentClassMixinFlatStructure.__init__(self, name=name, parameters=parameters, analog_ports=analog_ports, event_ports=event_ports, dynamics=dynamics) ComponentClassMixinNamespaceStructure.__init__(self, subnodes=subnodes, portconnections=portconnections) # Finalise initiation: self._resolve_transition_regime_names() # Store flattening Information: self._flattener = None # Is the finished component valid?: self._validate_self()
def __init__(self, name, parameters=None, analog_ports=[], event_ports=[], dynamics=None, subnodes=None, portconnections=None, regimes=None, aliases=None, state_variables=None): """Constructs a ComponentClass :param name: The name of the component. :param parameters: A list containing either |Parameter| objects or strings representing the parameter names. If ``None``, then the parameters are automatically inferred from the |Dynamics| block. :param analog_ports: A list of |AnalogPorts|, which will be the local |AnalogPorts| for this object. :param event_ports: A list of |EventPorts| objects, which will be the local event-ports for this object. If this is ``None``, then they will be automatically inferred from the dynamics block. :param dynamics: A |Dynamics| object, defining the local dynamics of the component. :param subnodes: A dictionary mapping namespace-names to sub-component. [Type: ``{string:|ComponentClass|, string:|ComponentClass|, string:|ComponentClass|}`` ] describing the namespace of subcomponents for this component. :param portconnections: A list of pairs, specifying the connections between the ports of the subcomponents in this component. These can be `(|NamespaceAddress|, |NamespaceAddress|)' or ``(string, string)``. :param interface: A shorthand way of specifying the **interface** for this component; |Parameters|, |AnalogPorts| and |EventPorts|. ``interface`` takes a list of these objects, and automatically resolves them by type into the correct types. Examples: >>> a = ComponentClass(name='MyComponent1') .. todo:: Point this towards and example of constructing ComponentClasses. This can't be here, because we also need to know about dynamics. For examples """ BaseComponentClass.__init__(self, name, parameters) # We can specify in the componentclass, and they will get forwarded to # the dynamics class. We check that we do not specify half-and-half: if dynamics is not None: if regimes or aliases or state_variables: err = "Either specify a 'dynamics' parameter, or " err += "state_variables /regimes/aliases, but not both!" raise NineMLRuntimeError(err) else: # We should always create a dynamics object, even is it is empty. FIXME: TGC 11/11/14, Why? @IgnorePep8 dynamics = dyn.Dynamics(regimes=regimes, aliases=aliases, state_variables=state_variables) self._query = componentqueryer.ComponentQueryer(self) # Ensure analog_ports is a list not an iterator analog_ports = list(analog_ports) event_ports = list(event_ports) # Check there aren't any duplicates in the port and parameter names assert_no_duplicates(p if isinstance(p, basestring) else p.name for p in chain(parameters if parameters else [], analog_ports, event_ports)) analog_receive_ports = [port for port in analog_ports if isinstance(port, AnalogReceivePort)] analog_reduce_ports = [port for port in analog_ports if isinstance(port, AnalogReducePort)] incoming_port_names = [p.name for p in chain(analog_receive_ports, analog_reduce_ports)] # EventPort, StateVariable and Parameter Inference: inferred_struct = InterfaceInferer(dynamics, incoming_port_names) inf_check = lambda l1, l2, desc: check_list_contain_same_items( l1, l2, desc1='Declared', desc2='Inferred', ignore=['t'], desc=desc) # Check any supplied parameters match: if parameters is not None: inf_check(self._parameters.keys(), inferred_struct.parameter_names, 'Parameters') else: self._parameters = dict((n, Parameter(n)) for n in inferred_struct.parameter_names) # Check any supplied state_variables match: if dynamics._state_variables: state_var_names = [p.name for p in dynamics.state_variables] inf_check(state_var_names, inferred_struct.state_variable_names, 'StateVariables') else: state_vars = dict((n, StateVariable(n)) for n in inferred_struct.state_variable_names) dynamics._state_variables = state_vars # Check Event Receive Ports Match: event_receive_ports = [port for port in event_ports if isinstance(port, EventReceivePort)] event_send_ports = [port for port in event_ports if isinstance(port, EventSendPort)] if event_receive_ports: # FIXME: not all OutputEvents are necessarily exposed as Ports, # so really we should just check that all declared output event # ports are in the list of inferred ports, not that the declared # list is identical to the inferred one. inf_check([p.name for p in event_receive_ports], inferred_struct.input_event_port_names, 'Event Ports In') # Check Event Send Ports Match: if event_send_ports: inf_check([p.name for p in event_send_ports], inferred_struct.output_event_port_names, 'Event Ports Out') else: event_ports = [] # Event ports not supplied, so lets use the inferred ones. for evt_port_name in inferred_struct.input_event_port_names: event_ports.append(EventReceivePort(name=evt_port_name)) for evt_port_name in inferred_struct.output_event_port_names: event_ports.append(EventSendPort(name=evt_port_name)) # Construct super-classes: ComponentClassMixinFlatStructure.__init__( self, analog_ports=analog_ports, event_ports=event_ports, dynamics=dynamics) ComponentClassMixinNamespaceStructure.__init__( self, subnodes=subnodes, portconnections=portconnections) # Finalise initiation: self._resolve_transition_regime_names() # Store flattening Information: self._flattener = None # Is the finished component valid?: self._validate_self()