def test_in_port_capnp(self): """Generate in port.""" in_port = InPort("index", as_delta_type(int), None, 0) capnp_in_port = dotdf_capnp.InPort.new_message() in_port.capnp(capnp_in_port) self.assertEqual(capnp_in_port.name, "index") self.assertEqual(dill.loads(capnp_in_port.type), as_delta_type(int)) self.assertEqual(capnp_in_port.optional, False)
def test_out_port_capnp(self): """Generate out port.""" out_port = OutPort("index", as_delta_type(int), None, None) capnp_out_port = dotdf_capnp.OutPort.new_message() out_port.capnp(capnp_out_port) self.assertEqual(capnp_out_port.name, "index") self.assertEqual(dill.loads(capnp_out_port.type), as_delta_type(int)) with self.assertRaises(AttributeError): dummy = capnp_out_port.optional
def test_out_port_capnp_no_index(self): """Generate out port when index not provided. In this case, name should be empty string. """ out_port = OutPort(NamespacedName("node_name", None), as_delta_type(int), None, None) capnp_out_port = dotdf_capnp.OutPort.new_message() out_port.capnp(capnp_out_port) self.assertEqual(capnp_out_port.name, "") self.assertEqual(dill.loads(capnp_out_port.type), as_delta_type(int))
def __init__(self, inputs: Union[List[Tuple[str, Type]], OrderedDict[str, Type]], outputs: Type = Void, name: str = None, lvl: int = logging.ERROR, node_key: Optional[str] = None, in_port_size: int = 0): self.name = "template_" + name if name else "template" self.lvl = lvl self.node_key = node_key self.in_port_size = in_port_size self._body_templates = [] # Cast list inputs to OrderedDict if not already if not isinstance(inputs, OrderedDict): if isinstance(inputs, list): inputs = OrderedDict(inputs) else: raise TypeError( 'Please provide types of input parameters as list') self.inputs = inputs_as_delta_types(inputs) self.outputs = as_delta_type(outputs) self._has_optional_inputs = False for in_type in self.inputs.values(): if isinstance(in_type, DOptional): self._has_optional_inputs = True
def inputs_as_delta_types( inputs: OrderedDict[str, Type], node_key: Optional[str] = None ) -> OrderedDict[str, Union[BaseDeltaType, DOptional]]: """Take ``inputs`` and convert to DeltaTypes, raising appropriate errors, skips and removes ``node_key``. Parameters ---------- inputs : Dict[str, Type] Dictionary of inputs that need to become DeltaTypes node_key : Optional[str], optional Node key for node param if available, by default None Returns ------- Dict[str, Union[BaseDeltaType, DOptional]] Dictionary of inputs as DeltaTypes """ for param_name, param_type in inputs.items(): if node_key == param_name and param_type == PythonNode: inputs.pop(node_key) continue delta_type_in = as_delta_type(param_type) if not isinstance(delta_type_in, (BaseDeltaType, DOptional)): raise DeltaTypeError(f"Unsupported type={param_type}") inputs[param_name] = delta_type_in return inputs
def merge_interactive(other: Optional['NodeTemplate'], func: Callable[[PythonNode], None], inputs: List[Tuple[str, Type]], outputs: Type, name: str = None, in_port_size: int = 0, latency: Latency = None, lvl: int = logging.ERROR, tags: List[str] = []) -> BodyTemplate: """Create a :py:class:`BodyTemplate` for the bodies and constructor created using the ``@Interactive`` decorator. Associate this with an existing or newly created ``NodeTemplate``. """ if len(inputs) == 0 and outputs == Void: raise DeltaIOError('Interactive node must have either an input ' 'or an output. Otherwise it may freeze ' 'the runtime simulator.') if not isinstance(inputs, list): raise TypeError('Please provide types of input parameters as list') inputs = inputs_as_delta_types(OrderedDict(inputs)) outputs = as_delta_type(outputs) body_template = InteractiveBodyTemplate(name, latency, lvl, func, tags) return NodeTemplate._standardised_merge(other, body_template, node_key=None, in_port_size=in_port_size, inputs=inputs, outputs=outputs)
def test_out_port_capnp_wiring(self): """Generate wiring. Should just call same method in destination.""" in_port = Mock() out_port = OutPort(NamespacedName("node_name", None), as_delta_type(int), in_port, None) out_port.capnp_wiring([], None) in_port.capnp_wiring.assert_called_with([], None)
def add_pa_out_port(self, name: str, t: Union[Type, BaseDeltaType]): """Add output protocol adaptor v2. Parameters ---------- type_ : Union[Type, BaseDeltaType] Data type. Returns ------- migen.Record .. todo:: Possibly use Size for data/valid/ready instead of int. """ df_t = as_delta_type(t) if isinstance(df_t, Optional): raise DeltaTypeError('out_port cannot be Optional') out_port = migen.Record([("data", df_t.size.val, migen.DIR_S_TO_M), ("valid", 1, migen.DIR_S_TO_M), ("ready", 1, migen.DIR_M_TO_S)]) self._dut.out_ports.append((name, out_port, t)) return out_port
def get_func_inputs_outputs( a_func: Callable, is_method: bool, node_key: Optional[str] = None ) -> Tuple[OrderedDict[str, Union[BaseDeltaType, DOptional]], Union[ BaseDeltaType, ForkedReturn]]: """Helper function to extract input and output types of a node function. Parameters ---------- a_func : Callable The function to analyse. is_method : bool Flag to specify if function is a class method. node_key : Optional[str] Keyword argument used for providing the node to the block, included for some logic purposes. Returns ------- OrderedDict[str, Union[BaseDeltaType, DOptional]] Types of the in parameters. Union[BaseDeltaType, ForkedReturn] Type of the output the node to be made. Raises ------ TypeError Raised if either the input or output types aren't specified in the function signature. """ func_args = signature(a_func).parameters outputs = signature(a_func).return_annotation inputs = OrderedDict() for i, (arg_name, arg_param) in enumerate(func_args.items()): # first argument should always be 'self' for a method if i == 0 and is_method: continue if arg_param.annotation == _empty: raise TypeError("Must specify the type of argument " + f"'{arg_name}' as annotation in " + f"function '{a_func.__name__}'") inputs[arg_name] = arg_param.annotation inputs = inputs_as_delta_types(inputs, node_key) if outputs == _empty: outputs = Void delta_type_out = as_delta_type(outputs) if delta_type_out is not Void: if not isinstance(delta_type_out, (BaseDeltaType, ForkedReturn)): raise DeltaTypeError(f"Unsupported type={outputs}") return inputs, delta_type_out
def add_out_port(self, port_destination: InPort, index=None): """Creates an out-port and adds it to my out-port store. Parameters ---------- index : Optional[str] If the out-port is one of several for this node, index specifies what part of the output is sent via this port. If the node has only one output, then this is `None`. port_destination : InPort The in-port that this out-port exports to. """ try: if issubclass(self.outputs, Void): raise DeltaIOError( f"Cannot make an out-port on node {self.name} " "with return type \'Void\'.\n" "Please either add the proper return type to the " "node definition or do not try to create an " "output data channel from this node.") except TypeError: pass if index is None: # out-port type is whole node return type # due to the strict typing the out type should match the in type if self.is_autogenerated: type_out = port_destination.port_type else: type_out = as_delta_type(self.outputs) self.out_ports.append( OutPort(NamespacedName(self.name, None), type_out, port_destination, self)) else: # out-port type is indexed node return type self.out_ports.append( OutPort(NamespacedName(self.name, index), as_delta_type(self.outputs.elem_dict[index]), port_destination, self)) # If this port is going into a port on a different graph, # flatten this graph into said graph into_graph = port_destination.node.graph if into_graph is not self.graph: into_graph.flatten(self.graph)
def test_node_serialisation(self): """Generate graph and check serialisation is correct.""" with DeltaGraph() as test_graph: self.func(2, 3) _, prog = serialise_graph(test_graph) self.assertEqual("_".join(prog.nodes[2].name.split("_")[:-1]), "add_print_exit") self.assertEqual(prog.nodes[2].bodies[0], 2) self.assertEqual(prog.nodes[2].inPorts[0].name, "a") self.assertEqual(dill.loads(prog.nodes[2].inPorts[0].type), as_delta_type(int)) self.assertEqual(prog.nodes[2].inPorts[0].optional, True) self.assertEqual(prog.nodes[2].inPorts[1].name, "b") self.assertEqual(dill.loads(prog.nodes[2].inPorts[1].type), as_delta_type(int)) self.assertEqual(prog.nodes[2].inPorts[1].optional, True) self.assertEqual(len(prog.nodes[2].inPorts), 2) self.assertEqual(len(prog.nodes[2].outPorts), 0) self.assertEqual(prog.bodies[2].python.dillImpl, test_graph.nodes[2].body.as_serialised) self.assertEqual(len(prog.graph), 2) self.assertEqual(prog.graph[0].srcNode, 0) self.assertEqual(prog.graph[0].srcOutPort, 0) self.assertEqual(prog.graph[0].destNode, 2) self.assertEqual(prog.graph[0].destInPort, 0) self.assertEqual(prog.graph[0].direct, False) self.assertEqual(prog.graph[1].srcNode, 1) self.assertEqual(prog.graph[1].srcOutPort, 0) self.assertEqual(prog.graph[1].destNode, 2) self.assertEqual(prog.graph[1].destInPort, 1) self.assertEqual(prog.graph[1].direct, False)
def test_in_port_capnp_wiring_direct(self): """In port has limit on port size.""" n = RealNode(DeltaGraph(), [], name='node_name') in_port = InPort("index", as_delta_type(int), n, 1) wire = dotdf_capnp.Wire.new_message() nodes = [dotdf_capnp.Node.new_message()] nodes[0].name = n.full_name nodes[0].init("inPorts", 1) nodes[0].inPorts[0].name = "index" in_port.capnp_wiring(nodes, wire) self.assertEqual(wire.destNode, 0) self.assertEqual(wire.destInPort, 0) self.assertEqual(wire.direct, True)
def test_in_port_capnp_wiring_direct(self): """In port has limit on port size.""" in_port = InPort(NamespacedName("node_name", "index"), as_delta_type(int), None, 1) wire = dotdf_capnp.Wire.new_message() nodes = [dotdf_capnp.Node.new_message()] nodes[0].name = "node_name" nodes[0].init("inPorts", 1) nodes[0].inPorts[0].name = "index" in_port.capnp_wiring(nodes, wire) self.assertEqual(wire.destNode, 0) self.assertEqual(wire.destInPort, 0) self.assertEqual(wire.direct, True)
def test_ports(self): """Test if the node wires are connected correctly and have the right type. """ interactive_node = self.graph.find_node_by_name("blah") dummy_node = self.graph.find_node_by_name("node") self.assertEqual(len(interactive_node.in_ports), 1) self.assertEqual(len(interactive_node.out_ports), 1) self.assertTupleEqual(interactive_node.out_ports[0].port_name, (interactive_node.name, None)) self.assertEqual(str(interactive_node.out_ports[0].port_type), str(as_delta_type(int))) self.assertEqual(len(dummy_node.in_ports), 1) self.assertEqual(len(dummy_node.out_ports), 1) self.assertTupleEqual(interactive_node.out_ports[0].port_name, (interactive_node.name, None)) self.assertEqual(str(dummy_node.out_ports[0].port_type), str(as_delta_type(str))) self.assertEqual(interactive_node.out_ports[0].destination.node, dummy_node)
def test_in_port_capnp_wiring(self): """Generate wiring.""" in_port = InPort(NamespacedName("node_name", "index"), as_delta_type(int), None, 0) wire = dotdf_capnp.Wire.new_message() nodes = [dotdf_capnp.Node.new_message() for _ in range(3)] nodes[0].name = "fake_name" nodes[1].name = "fake_name" nodes[2].name = "node_name" nodes[2].init("inPorts", 3) nodes[2].inPorts[0].name = "fake_name" nodes[2].inPorts[1].name = "index" nodes[2].inPorts[2].name = "fake_name" in_port.capnp_wiring(nodes, wire) self.assertEqual(wire.destNode, 2) self.assertEqual(wire.destInPort, 1) self.assertEqual(wire.direct, False)
def test_in_port_capnp_wiring(self): """Generate wiring.""" n = RealNode(DeltaGraph(), [], name='node_name') in_port = InPort("index", as_delta_type(int), n, 0) wire = dotdf_capnp.Wire.new_message() nodes = [dotdf_capnp.Node.new_message() for _ in range(3)] nodes[0].name = "fake_name" nodes[1].name = "fake_name" nodes[2].name = n.full_name nodes[2].init("inPorts", 3) nodes[2].inPorts[0].name = "fake_name" nodes[2].inPorts[1].name = "index" nodes[2].inPorts[2].name = "fake_name" in_port.capnp_wiring(nodes, wire) self.assertEqual(wire.destNode, 2) self.assertEqual(wire.destInPort, 1) self.assertEqual(wire.direct, False)
def merge_migenblock(other: Optional['NodeTemplate'], body_template: BodyTemplate, inputs: OrderedDict[str, Type], outputs: Type,) -> BodyTemplate: """Create a :py:class:`BodyTemplate` for the bodies and constructor for migen based bodies. Associate this with an existing or newly created :py:class:`NodeTemplate`. """ inputs = inputs_as_delta_types(inputs) outputs = as_delta_type(outputs) return NodeTemplate._standardised_merge(other=other, body_template=body_template, inputs=inputs, outputs=outputs, node_key=None, in_port_size=0)
def add_in_port(self, arg_name: str, in_type: Type, in_port_size: int = 0): """Creates an in-port and adds it to my in-port store. Parameters ---------- arg_name : str Name of the argument this port supplies. in_type : Type The type that is expected to be supplied for this port. in_port_size: int Maximum size of the in ports. If 0 then size is unlimited. Returns ------- InPort The created port. """ my_port = InPort(NamespacedName(self.name, arg_name), as_delta_type(in_type), self, in_port_size) self.in_ports[my_port.port_name] = my_port return my_port
def outputs_as_delta_types( outputs: typing.OrderedDict[str, typing.Type], ) -> typing.OrderedDict[str, BaseDeltaType]: """Take ``outputs`` and convert to DeltaTypes, raising appropriate errors. Parameters ---------- outputs : OrderedDict[str, Type] Dictionary of output types that need to become DeltaTypes Returns ------- Dict[str, BaseDeltaType] Dictionary of outputs as DeltaTypes """ for out_name, out_type in outputs.items(): delta_type_out = as_delta_type(out_type) if not isinstance(delta_type_out, BaseDeltaType): raise DeltaTypeError(f"Unsupported out type = {out_type}") outputs[out_name] = delta_type_out return outputs
def test_as_delta_type(self): """Test conversion from python to Deltaflow data types.""" # special self.assertEqual(as_delta_type(object), Top()) self.assertEqual(as_delta_type(type(object)), Top()) self.assertEqual(as_delta_type(type), Top()) self.assertEqual(as_delta_type('random_text'), Top()) with self.assertRaises(DeltaTypeError): as_delta_type(None) with self.assertRaises(DeltaTypeError): as_delta_type(type(None)) # primitive self.assertEqual(as_delta_type(bool), Bool()) self.assertEqual(as_delta_type(np.bool_), Bool()) self.assertEqual(as_delta_type(int), Int(Size(32))) self.assertEqual(as_delta_type(np.int8), Char()) self.assertEqual(as_delta_type(np.int16), Int(Size(16))) self.assertEqual(as_delta_type(np.int32), Int(Size(32))) self.assertEqual(as_delta_type(np.int64), Int(Size(64))) self.assertEqual(as_delta_type(np.uint8), Char()) self.assertEqual(as_delta_type(np.uint16), UInt(Size(16))) self.assertEqual(as_delta_type(np.uint32), UInt(Size(32))) self.assertEqual(as_delta_type(np.uint64), UInt(Size(64))) self.assertEqual(as_delta_type(float), Float()) self.assertEqual(as_delta_type(np.float32), Float(Size(32))) self.assertEqual(as_delta_type(np.float64), Float(Size(64))) self.assertEqual(as_delta_type(complex), Complex()) self.assertEqual(as_delta_type(np.complex64), Complex(Size(64))) self.assertEqual(as_delta_type(np.complex128), Complex(Size(128))) # compound with self.assertRaises(DeltaTypeError): as_delta_type(typing.Tuple[int, bool]) with self.assertRaises(DeltaTypeError): as_delta_type(typing.List[int]) self.assertNotEqual(as_delta_type(str), Array(Char(), Size(1024))) self.assertEqual(as_delta_type(str), Str()) self.assertEqual(as_delta_type(RecBI), Record(RecBI)) # numpy compound self.assertEqual(as_delta_type(Array(int, Size(5)).as_numpy_type()), Array(int, Size(5))) self.assertEqual(as_delta_type(Str().as_numpy_type()), Str()) self.assertEqual( as_delta_type(Tuple([int, bool, float]).as_numpy_type()), Tuple([int, bool, float])) self.assertEqual(as_delta_type(Record(RecBI).as_numpy_type()), Record(RecBI)) self.assertEqual( as_delta_type(Union([bool, float, int]).as_numpy_type()), Union([bool, float, int])) # from string self.assertEqual(as_delta_type('bool'), Bool()) self.assertEqual(as_delta_type('\'bool\''), Bool()) self.assertEqual(as_delta_type('np.bool_'), Bool()) self.assertEqual(as_delta_type('int'), Int(Size(32))) self.assertEqual(as_delta_type('np.int32'), Int(Size(32))) self.assertEqual(as_delta_type('np.uint32'), UInt(Size(32))) self.assertEqual(as_delta_type('float'), Float()) self.assertEqual(as_delta_type('np.float32'), Float(Size(32))) self.assertEqual(as_delta_type('complex'), Complex()) self.assertEqual(as_delta_type('np.complex64'), Complex(Size(64))) self.assertEqual(as_delta_type('str'), Str()) self.assertEqual(as_delta_type("Int(Size(32))"), Int(Size(32))) # 'RecBI' is out of scope when the string is evaluated self.assertEqual(as_delta_type('RecBI'), Top())
def test_as_delta_type(self): """Test conversion from python to Deltaflow data types.""" # special self.assertEqual(as_delta_type(object), Top()) self.assertEqual(as_delta_type(type(object)), Top()) self.assertEqual(as_delta_type(type), Top()) self.assertEqual(as_delta_type(Void), Void) with self.assertRaises(DeltaTypeError): as_delta_type(None) with self.assertRaises(DeltaTypeError): as_delta_type(type(None)) # primitive self.assertNotEqual(as_delta_type(bool), DUInt(DSize(1))) self.assertEqual(as_delta_type(bool), DBool()) self.assertEqual(as_delta_type(np.bool_), DBool()) self.assertEqual(as_delta_type(int), DInt(DSize(32))) self.assertEqual(as_delta_type(np.int8), DChar()) self.assertEqual(as_delta_type(np.int16), DInt(DSize(16))) self.assertEqual(as_delta_type(np.int32), DInt(DSize(32))) self.assertEqual(as_delta_type(np.int64), DInt(DSize(64))) self.assertEqual(as_delta_type(np.uint8), DChar()) self.assertEqual(as_delta_type(np.uint16), DUInt(DSize(16))) self.assertEqual(as_delta_type(np.uint32), DUInt(DSize(32))) self.assertEqual(as_delta_type(np.uint64), DUInt(DSize(64))) self.assertEqual(as_delta_type(float), DFloat()) self.assertEqual(as_delta_type(np.float32), DFloat(DSize(32))) self.assertEqual(as_delta_type(np.float64), DFloat(DSize(64))) self.assertEqual(as_delta_type(complex), DComplex()) self.assertEqual(as_delta_type(np.complex64), DComplex(DSize(64))) self.assertEqual(as_delta_type(np.complex128), DComplex(DSize(128))) # compound with self.assertRaises(DeltaTypeError): as_delta_type(Tuple[int, bool]) with self.assertRaises(DeltaTypeError): as_delta_type(List[int]) self.assertNotEqual(as_delta_type(str), DArray(DChar(), DSize(1024))) self.assertEqual(as_delta_type(str), DStr()) self.assertEqual(as_delta_type(RecBI), DRecord(RecBI)) # numpy compound self.assertEqual(as_delta_type(DArray(int, DSize(5)).as_numpy_type()), DArray(int, DSize(5))) self.assertEqual(as_delta_type(DStr().as_numpy_type()), DStr()) self.assertEqual( as_delta_type(DTuple([int, bool, float]).as_numpy_type()), DTuple([int, bool, float]) ) self.assertEqual(as_delta_type(DRecord(RecBI).as_numpy_type()), DRecord(RecBI)) self.assertEqual( as_delta_type(DUnion([bool, float, int]).as_numpy_type()), DUnion([bool, float, int]))