Exemple #1
0
 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)
Exemple #2
0
 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
Exemple #3
0
 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)
Exemple #7
0
 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)
Exemple #11
0
    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)
Exemple #12
0
 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)
Exemple #13
0
 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)
Exemple #14
0
    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)
Exemple #15
0
 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)
Exemple #16
0
 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
Exemple #19
0
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
Exemple #20
0
    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())
Exemple #21
0
    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]))