Ejemplo n.º 1
0
def test_blind_branch() -> None:

    scene = Scene("s1")
    obj = SceneObject("test_name", Test.__name__)
    scene.objects.append(obj)
    project = Project("p1", "s1")
    ap1 = ActionPoint("ap1", Position())
    project.action_points.append(ap1)

    ac1 = Action("ac1", f"{obj.id}/test", flows=[Flow(outputs=["bool_res"])])
    ap1.actions.append(ac1)

    ac2 = Action("ac2", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac2)

    ac3 = Action("ac3", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac3)

    ac4 = Action("ac4", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac4)

    project.logic.append(LogicItem(LogicItem.START, ac1.id))

    project.logic.append(LogicItem(ac1.id, ac2.id, ProjectLogicIf(f"{ac1.id}/default/0", json.dumps(True))))
    project.logic.append(LogicItem(ac1.id, ac3.id, ProjectLogicIf(f"{ac1.id}/default/0", json.dumps(False))))

    project.logic.append(LogicItem(ac2.id, ac4.id))
    project.logic.append(LogicItem(ac4.id, LogicItem.END))

    with pytest.raises(SourceException, match=f"Action {ac3.name} has no outputs."):
        program_src({Test.__name__: Test}, CachedProject(project), CachedScene(scene))
Ejemplo n.º 2
0
def check_action_params(
    scene: CachedScene, project: CachedProject, action: common.Action, object_action: ObjectAction
) -> None:

    _, action_type = action.parse_type()

    assert action_type == object_action.name

    if len(object_action.parameters) != len(action.parameters):
        raise Arcor2Exception("Unexpected number of parameters.")

    for req_param in object_action.parameters:

        param = action.parameter(req_param.name)

        if param.type == common.ActionParameter.TypeEnum.CONSTANT:

            const = project.constant(param.str_from_value())

            param_meta = object_action.parameter(param.name)
            if param_meta.type != const.type:
                raise Arcor2Exception("Param type does not match constant type.")

        elif param.type == common.ActionParameter.TypeEnum.LINK:

            parsed_link = param.parse_link()

            if parsed_link.action_id == action.id:
                raise Arcor2Exception("Can't use own result as a parameter.")

            outputs = project.action(parsed_link.action_id).flow(parsed_link.flow_name).outputs

            assert len(outputs) == len(object_action.returns)

            param_meta = object_action.parameter(param.name)
            if param_meta.type != object_action.returns[parsed_link.output_index]:
                raise Arcor2Exception("Param type does not match action output type.")

        else:

            if param.type not in known_parameter_types():
                raise Arcor2Exception(f"Parameter {param.name} of action {action.name} has unknown type: {param.type}.")

            try:
                plugin_from_type_name(param.type).parameter_value(
                    get_types_dict(), scene, project, action.id, param.name
                )
            except ParameterPluginException as e:
                raise Arcor2Exception(f"Parameter {param.name} of action {action.name} has invalid value. {str(e)}")
Ejemplo n.º 3
0
def check_flows(parent: Union[CachedProject, common.ProjectFunction],
                action: common.Action, action_meta: ObjectAction) -> None:
    """Raises exception if there is something wrong with flow(s).

    :param parent:
    :param action:
    :param action_meta:
    :return:
    """

    flow = action.flow(
    )  # searches default flow (just this flow is supported so far)

    # it is ok to not specify any output (if the values are not going to be used anywhere)
    # return value(s) won't be stored in variable(s)
    if not flow.outputs:
        return

    # otherwise, all return values have to be stored in variables
    if len(flow.outputs) != len(action_meta.returns):
        raise Arcor2Exception(
            "Number of the flow outputs does not match the number of action outputs."
        )

    for output in flow.outputs:
        hlp.is_valid_identifier(output)

    outputs: Set[str] = set()

    for act in parent.actions:
        for fl in act.flows:
            for output in fl.outputs:
                if output in outputs:
                    raise Arcor2Exception(f"Output '{output}' is not unique.")
Ejemplo n.º 4
0
def test_constant() -> None:

    scene = Scene("s1")
    obj = SceneObject("test_name", Test.__name__)
    scene.objects.append(obj)
    project = Project("p1", "s1")
    ap1 = ActionPoint("ap1", Position())
    project.action_points.append(ap1)

    const_value = 1234
    const = ProjectParameter("int_const", "integer", json.dumps(const_value))
    project.parameters.append(const)

    ac1 = Action(
        "ac1",
        f"{obj.id}/test_par",
        flows=[Flow()],
        parameters=[
            ActionParameter("param", ActionParameter.TypeEnum.CONSTANT,
                            json.dumps(const.id))
        ],
    )

    ap1.actions.append(ac1)

    project.logic.append(LogicItem(LogicItem.START, ac1.id))
    project.logic.append(LogicItem(ac1.id, LogicItem.END))

    src = program_src({Test.__name__: Test}, CachedProject(project),
                      CachedScene(scene))

    assert f"{const.name} = {const_value}" in src
    assert f"test_name.{Test.test_par.__name__}({const.name}, an='ac1')" in src
Ejemplo n.º 5
0
def test_prev_result() -> None:

    scene = Scene("s1")
    obj = SceneObject("test_name", Test.__name__)
    scene.objects.append(obj)
    project = Project("p1", "s1")
    ap1 = ActionPoint("ap1", Position())
    project.action_points.append(ap1)

    ac1 = Action("ac1",
                 f"{obj.id}/{Test.get_int.__name__}",
                 flows=[Flow(outputs=["res"])])
    ap1.actions.append(ac1)

    ac2 = Action(
        "ac2",
        f"{obj.id}/{Test.test_par.__name__}",
        flows=[Flow()],
        parameters=[
            ActionParameter("param", ActionParameter.TypeEnum.LINK,
                            json.dumps(f"{ac1.id}/default/0"))
        ],
    )
    ap1.actions.append(ac2)

    project.logic.append(LogicItem(LogicItem.START, ac1.id))
    project.logic.append(LogicItem(ac1.id, ac2.id))
    project.logic.append(LogicItem(ac2.id, LogicItem.END))

    src = program_src({Test.__name__: Test}, CachedProject(project),
                      CachedScene(scene))

    assert f"res = test_name.{Test.get_int.__name__}(an='{ac1.name}')" in src
    assert f"test_name.{Test.test_par.__name__}(res, an='{ac2.name}')" in src

    # test wrong order of logic
    project.logic.clear()

    project.logic.append(LogicItem(LogicItem.START, ac2.id))
    project.logic.append(LogicItem(ac2.id, ac1.id))
    project.logic.append(LogicItem(ac1.id, LogicItem.END))

    with pytest.raises(SourceException):
        program_src({Test.__name__: Test}, CachedProject(project),
                    CachedScene(scene))
Ejemplo n.º 6
0
def test_get_value() -> None:

    p = Pose(Position(1, 2, 3), Orientation(1, 0, 0, 0))

    scene = Scene("s1")
    obj = SceneObject("test_name", TestObject.__name__)
    scene.objects.append(obj)
    project = Project("p1", "s1")
    ap1 = ActionPoint("ap1", Position(1, 0, 0))
    project.action_points.append(ap1)
    ap2 = ActionPoint("ap2", Position(), parent=ap1.id)
    project.action_points.append(ap2)

    ori1 = NamedOrientation("ori1", p.orientation)

    ap2.orientations.append(ori1)

    invalid_param_name = "invalid_param"

    ac1 = Action(
        "ac1",
        f"{obj.id}/{TestObject.action.__name__}",
        parameters=[
            ActionParameter(param_name, PosePlugin.type_name(),
                            json.dumps(ori1.id)),
            ActionParameter(invalid_param_name, PosePlugin.type_name(),
                            json.dumps("non_sense")),
        ],
    )

    ap1.actions.append(ac1)

    cscene = CachedScene(scene)
    cproject = CachedProject(project)

    with pytest.raises(Arcor2Exception):
        PosePlugin.parameter_value(type_defs, cscene, cproject, ac1.id,
                                   "non_sense")

    with pytest.raises(Arcor2Exception):
        PosePlugin.parameter_value(type_defs, cscene, cproject, "non_sense",
                                   param_name)

    with pytest.raises(ParameterPluginException):
        PosePlugin.parameter_value(type_defs, cscene, cproject, ac1.id,
                                   invalid_param_name)

    value = PosePlugin.parameter_value(type_defs, cscene, cproject, ac1.id,
                                       param_name)
    exe_value = PosePlugin.parameter_execution_value(type_defs, cscene,
                                                     cproject, ac1.id,
                                                     param_name)

    assert value == value
    assert value != exe_value
Ejemplo n.º 7
0
def test_get_value() -> None:

    img = Image.new("RGB", (320, 240))

    scene = Scene("s1", "s1")
    obj = SceneObject("test_name", TestObject.__name__)
    scene.objects.append(obj)
    project = Project("p1", "s1")
    ap1 = ActionPoint("ap1", Position(1, 0, 0))
    project.action_points.append(ap1)

    invalid_param_name = "invalid_param"

    ac1 = Action(
        "ac1",
        f"{obj.id}/{TestObject.action.__name__}",
        parameters=[
            ActionParameter(param_name, ImagePlugin.type_name(),
                            ImagePlugin.value_to_json(img)),
            ActionParameter(invalid_param_name, ImagePlugin.type_name(),
                            json.dumps("non_sense")),
        ],
    )

    ap1.actions.append(ac1)

    cscene = CachedScene(scene)
    cproject = CachedProject(project)

    with pytest.raises(Arcor2Exception):
        ImagePlugin.parameter_value(type_defs, cscene, cproject, ac1.id,
                                    "non_sense")

    with pytest.raises(Arcor2Exception):
        ImagePlugin.parameter_value(type_defs, cscene, cproject, "non_sense",
                                    param_name)

    with pytest.raises(ParameterPluginException):
        ImagePlugin.parameter_value(type_defs, cscene, cproject, ac1.id,
                                    invalid_param_name)

    value = ImagePlugin.parameter_value(type_defs, cscene, cproject, ac1.id,
                                        param_name)
    exe_value = ImagePlugin.parameter_execution_value(type_defs, cscene,
                                                      cproject, ac1.id,
                                                      param_name)

    assert value == value
    assert value == exe_value
Ejemplo n.º 8
0
def test_get_value() -> None:

    scene = Scene("s1", "s1")
    obj = SceneObject("test_name", TestObject.__name__)
    prj = ProjectRobotJoints("name", obj.id, [Joint("name", 0.333)])
    scene.objects.append(obj)
    project = Project("p1", "s1")
    ap1 = ActionPoint("ap1", Position(1, 0, 0))
    ap1.robot_joints.append(prj)
    project.action_points.append(ap1)

    invalid_param_name = "invalid_param"

    act = Action(
        "ac1",
        f"{obj.id}/{TestObject.action.__name__}",
        parameters=[
            ActionParameter(param_name, JointsPlugin.type_name(),
                            json.dumps(prj.id)),
            ActionParameter(invalid_param_name, JointsPlugin.type_name(),
                            json.dumps("non_sense")),
        ],
    )

    ap1.actions.append(act)

    cscene = CachedScene(scene)
    cproject = CachedProject(project)

    with pytest.raises(Arcor2Exception):
        JointsPlugin.parameter_value(type_defs, cscene, cproject, act.id,
                                     "non_sense")

    with pytest.raises(Arcor2Exception):
        JointsPlugin.parameter_value(type_defs, cscene, cproject, "non_sense",
                                     param_name)

    with pytest.raises(ParameterPluginException):
        JointsPlugin.parameter_value(type_defs, cscene, cproject, act.id,
                                     invalid_param_name)

    value = JointsPlugin.parameter_value(type_defs, cscene, cproject, act.id,
                                         param_name)
    exe_value = JointsPlugin.parameter_execution_value(type_defs, cscene,
                                                       cproject, act.id,
                                                       param_name)

    assert value == value
    assert value == exe_value
Ejemplo n.º 9
0
def find_object_action(obj_types: ObjectTypeDict, scene: CachedScene, action: Action) -> ObjectAction:

    obj_id, action_type = action.parse_type()
    obj = scene.object(obj_id)
    obj_type = obj_types[obj.type]

    try:
        act = obj_type.actions[action_type]
    except KeyError:
        raise Arcor2Exception("Unknown type of action.")

    if act.disabled:
        raise Arcor2Exception("Action is disabled.")

    return act
Ejemplo n.º 10
0
def find_object_action(action: common.Action) -> object_type.ObjectAction:

    assert glob.SCENE

    obj_id, action_type = action.parse_type()
    obj = glob.SCENE.object_or_service(obj_id)

    if obj.type not in glob.ACTIONS:
        raise Arcor2Exception("Unknown object/service type.")

    for act in glob.ACTIONS[obj.type]:
        if act.name == action_type:
            if act.disabled:
                raise Arcor2Exception("Action is disabled.")
            return act
    raise Arcor2Exception("Unknown type of action.")
Ejemplo n.º 11
0
    def test_get_value(self, val: str) -> None:

        scene = Scene("s1")
        obj = SceneObject("test_name", TestObject.__name__)
        scene.objects.append(obj)
        project = Project("p1", "s1")
        ap1 = ActionPoint("ap1", Position())
        project.action_points.append(ap1)

        invalid_param_name = "invalid_param"

        ac1 = Action(
            "ac1",
            f"{obj.id}/{TestObject.action.__name__}",
            parameters=[
                ActionParameter(param_name, StringPlugin.type_name(),
                                StringPlugin.value_to_json(val)),
                ActionParameter(invalid_param_name, StringPlugin.type_name(),
                                json.dumps(666)),
            ],
        )

        ap1.actions.append(ac1)

        cscene = CachedScene(scene)
        cproject = CachedProject(project)

        with pytest.raises(Arcor2Exception):
            StringPlugin.parameter_value({}, cscene, cproject, ac1.id,
                                         "non_sense")

        with pytest.raises(Arcor2Exception):
            StringPlugin.parameter_value({}, cscene, cproject, "non_sense",
                                         param_name)

        with pytest.raises(ParameterPluginException):
            StringPlugin.parameter_value({}, cscene, cproject, ac1.id,
                                         invalid_param_name)

        value = StringPlugin.parameter_value({}, cscene, cproject, ac1.id,
                                             param_name)
        exe_value = StringPlugin.parameter_execution_value({}, cscene,
                                                           cproject, ac1.id,
                                                           param_name)

        assert value == val
        assert value == exe_value
Ejemplo n.º 12
0
def find_object_action(scene: CachedScene, action: common.Action) -> ObjectAction:

    obj_id, action_type = action.parse_type()
    obj = scene.object(obj_id)

    try:
        obj_type = glob.OBJECT_TYPES[obj.type]
    except KeyError:
        raise Arcor2Exception("Unknown object type.")

    try:
        act = obj_type.actions[action_type]
    except KeyError:
        raise Arcor2Exception("Unknown type of action.")

    if act.disabled:
        raise Arcor2Exception("Action is disabled.")

    return act
Ejemplo n.º 13
0
def check_action_params(project: common.Project, action: common.Action, object_action: object_type.ObjectAction) \
        -> None:

    assert glob.SCENE

    _, action_type = action.parse_type()

    assert action_type == object_action.name

    if len(object_action.parameters) != len(action.parameters):
        raise Arcor2Exception("Unexpected number of parameters.")

    for req_param in object_action.parameters:
        for given_param in action.parameters:
            if req_param.name == given_param.id and req_param.type == given_param.type:
                break
        else:
            raise Arcor2Exception(
                f"Action parameter {req_param.name}/{req_param.type} is not set or has invalid type."
            )

    # check values of parameters
    for param in action.parameters:

        if param.type not in PARAM_PLUGINS:
            raise Arcor2Exception(
                f"Parameter {param.id} of action {action.name} has unknown type: {param.type}."
            )

        try:
            PARAM_PLUGINS[param.type].value(glob.TYPE_DEF_DICT, glob.SCENE,
                                            project, action.id, param.id)
        except ParameterPluginException as e:
            raise Arcor2Exception(
                f"Parameter {param.id} of action {action.name} has invalid value. {str(e)}"
            )
Ejemplo n.º 14
0
def test_branched_output() -> None:

    scene = Scene("s1")
    obj = SceneObject("test_name", "Test")
    scene.objects.append(obj)
    project = Project("p1", "s1")
    ap1 = ActionPoint("ap1", Position())
    project.action_points.append(ap1)

    ac1 = Action("ac1", f"{obj.id}/test", flows=[Flow(outputs=["bool_res"])])
    ap1.actions.append(ac1)

    ac2 = Action("ac2", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac2)

    ac3 = Action("ac3", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac3)

    ac4 = Action("ac4", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac4)

    project.logic.append(LogicItem(LogicItem.START, ac1.id))

    project.logic.append(
        LogicItem(ac1.id, ac2.id,
                  ProjectLogicIf(f"{ac1.id}/default/0", json.dumps(True))))
    project.logic.append(
        LogicItem(ac1.id, ac3.id,
                  ProjectLogicIf(f"{ac1.id}/default/0", json.dumps(False))))

    project.logic.append(LogicItem(ac2.id, ac4.id))
    project.logic.append(LogicItem(ac3.id, ac4.id))
    project.logic.append(LogicItem(ac4.id, LogicItem.END))

    src = program_src({Test.__name__: Test}, CachedProject(project),
                      CachedScene(scene))
    parse(src)
    """
    bool_res = test_name.test(res.ac1)
    if bool_res == False:
        test_name.test(res.ac3)
    elif bool_res == True:
        test_name.test(res.ac2)
    test_name.test(res.ac4)
    """

    spl = src.splitlines()

    ac1_idx = subs_index(spl, "bool_res = test_name.test(an='ac1')")

    if_bool_res_false_idx = subs_index(spl, "if bool_res == False:")
    assert if_bool_res_false_idx > ac1_idx
    assert cntsp(spl[if_bool_res_false_idx]) == cntsp(spl[ac1_idx])
    assert "test_name.test(an='ac3')" in spl[if_bool_res_false_idx + 1]
    assert cntsp(spl[if_bool_res_false_idx]) == cntsp(
        spl[if_bool_res_false_idx + 1]) - TAB

    if_bool_res_true_idx = subs_index(spl, "if bool_res == True:")
    assert if_bool_res_true_idx > ac1_idx
    assert cntsp(spl[if_bool_res_true_idx]) == cntsp(spl[ac1_idx])
    assert "test_name.test(an='ac2')" in spl[if_bool_res_true_idx + 1]
    assert cntsp(spl[if_bool_res_true_idx]) == cntsp(
        spl[if_bool_res_true_idx + 1]) - TAB

    ac4_idx = subs_index(spl, "test_name.test(an='ac4')")
    assert ac4_idx > if_bool_res_false_idx
    assert ac4_idx > if_bool_res_true_idx
    assert cntsp(spl[ac4_idx]) == cntsp(spl[ac1_idx])
Ejemplo n.º 15
0
def test_branched_output_2() -> None:

    scene = Scene("s1")
    obj = SceneObject("test_name", Test.__name__)
    scene.objects.append(obj)
    project = Project("p1", "s1")
    ap1 = ActionPoint("ap1", Position())
    project.action_points.append(ap1)

    ac1 = Action("ac1", f"{obj.id}/test", flows=[Flow(outputs=["bool_res"])])
    ap1.actions.append(ac1)

    ac2 = Action("ac2", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac2)

    ac3 = Action("ac3", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac3)

    ac4 = Action("ac4", f"{obj.id}/test", flows=[Flow(outputs=["bool2_res"])])
    ap1.actions.append(ac4)

    ac5 = Action("ac5", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac5)

    ac6 = Action("ac6", f"{obj.id}/test", flows=[Flow()])
    ap1.actions.append(ac6)

    project.logic.append(LogicItem(LogicItem.START, ac1.id))

    project.logic.append(
        LogicItem(ac1.id, ac2.id,
                  ProjectLogicIf(f"{ac1.id}/default/0", json.dumps(True))))
    project.logic.append(
        LogicItem(ac1.id, ac4.id,
                  ProjectLogicIf(f"{ac1.id}/default/0", json.dumps(False))))

    project.logic.append(LogicItem(ac2.id, ac3.id))
    project.logic.append(LogicItem(ac3.id, ac6.id))

    project.logic.append(
        LogicItem(ac4.id, ac5.id,
                  ProjectLogicIf(f"{ac4.id}/default/0", json.dumps(True))))
    project.logic.append(LogicItem(ac5.id, ac6.id))
    project.logic.append(LogicItem(ac6.id, LogicItem.END))

    project.logic.append(
        LogicItem(ac4.id, LogicItem.END,
                  ProjectLogicIf(f"{ac4.id}/default/0", json.dumps(False))))

    src = program_src({Test.__name__: Test}, CachedProject(project),
                      CachedScene(scene))
    parse(src)
    """
    bool_res = test_name.test(res.ac1)
    if (bool_res == False):
        bool2_res = test_name.test(res.ac4)
        if (bool2_res == False):
            continue
        elif (bool2_res == True):
            test_name.test(res.ac5)
    elif (bool_res == True):
        test_name.test(res.ac2)
        test_name.test(res.ac3)
    test_name.test(res.ac6)
    """

    spl = src.splitlines()

    # it has to be robust against changed order of blocks
    ac1_idx = subs_index(spl, "bool_res = test_name.test(an='ac1')")

    if_bool_res_false_idx = subs_index(spl, "if (bool_res == False):")
    assert if_bool_res_false_idx > ac1_idx
    assert cntsp(spl[ac1_idx]) == cntsp(spl[if_bool_res_false_idx])

    bool2_res_idx = subs_index(spl, "bool2_res = test_name.test(an='ac4')")
    assert bool2_res_idx > if_bool_res_false_idx
    assert cntsp(spl[if_bool_res_false_idx]) == cntsp(spl[bool2_res_idx]) - TAB

    if_bool_2_res_false_idx = subs_index(spl, "if (bool2_res == False):")
    assert cntsp(spl[if_bool_2_res_false_idx]) == cntsp(spl[bool2_res_idx])
    assert if_bool_2_res_false_idx > bool2_res_idx
    assert "continue" in spl[if_bool_2_res_false_idx + 1]
    assert cntsp(
        spl[bool2_res_idx]) == cntsp(spl[if_bool_2_res_false_idx + 1]) - TAB

    if_bool_2_res_true_idx = subs_index(spl, "if (bool2_res == True):")
    assert if_bool_2_res_true_idx > bool2_res_idx
    assert "test_name.test(an='ac5')" in spl[if_bool_2_res_true_idx + 1]
    assert cntsp(spl[if_bool_2_res_true_idx]) == cntsp(
        spl[if_bool_2_res_true_idx + 1]) - TAB

    if_bool_res_true_idx = subs_index(spl, "if (bool_res == True):")
    assert if_bool_res_true_idx > ac1_idx
    assert cntsp(spl[ac1_idx]) == cntsp(spl[if_bool_res_true_idx])

    assert "test_name.test(an='ac2')" in spl[if_bool_res_true_idx + 1]
    assert cntsp(spl[if_bool_res_true_idx]) == cntsp(
        spl[if_bool_res_true_idx + 1]) - TAB

    assert "test_name.test(an='ac3')" in spl[if_bool_res_true_idx + 2]
    assert cntsp(spl[if_bool_res_true_idx]) == cntsp(
        spl[if_bool_res_true_idx + 2]) - TAB

    ac6_idx = subs_index(spl, "test_name.test(an='ac6')")
    assert cntsp(spl[ac1_idx]) == cntsp(spl[ac6_idx])
    assert ac6_idx > if_bool_2_res_false_idx
    assert ac6_idx > if_bool_2_res_true_idx
Ejemplo n.º 16
0
from arcor2.data.common import (
    Action,
    ActionPoint,
    Flow,
    LogicItem,
    Position,
    Project,
    ProjectLogicIf,
    Scene,
    SceneObject,
)
from arcor2.exceptions import Arcor2Exception
from arcor2.logic import check_for_loops

obj = SceneObject("test_name", "Test")
ac1 = Action("ac1", f"{obj.id}/test", flows=[Flow(outputs=["bool_res"])])
ac2 = Action("ac2", f"{obj.id}/test", flows=[Flow()])
ac3 = Action("ac3", f"{obj.id}/test", flows=[Flow()])
ac4 = Action("ac4", f"{obj.id}/test", flows=[Flow()])


@pytest.fixture()
def scene() -> Scene:

    scene = Scene("s1", "s1")
    scene.objects.append(obj)
    return scene


@pytest.fixture()
def project() -> UpdateableCachedProject:
Ejemplo n.º 17
0
def check_action_params(scene: CachedScene, project: CachedProject,
                        action: common.Action,
                        object_action: ObjectAction) -> None:

    _, action_type = action.parse_type()

    assert action_type == object_action.name

    if len(object_action.parameters) != len(action.parameters):
        raise Arcor2Exception("Unexpected number of parameters.")

    for req_param in object_action.parameters:

        param = action.parameter(req_param.name)

        if param.type == common.ActionParameter.TypeEnum.PROJECT_PARAMETER:

            pparam = project.parameter(param.str_from_value())

            param_meta = object_action.parameter(param.name)
            if param_meta.type != pparam.type:
                raise Arcor2Exception(
                    "Action parameter type does not match project parameter type."
                )

        elif param.type == common.ActionParameter.TypeEnum.LINK:

            parsed_link = param.parse_link()

            if parsed_link.action_id == action.id:
                raise Arcor2Exception("Can't use own result as a parameter.")

            parent_action = project.action(parsed_link.action_id)
            source_action_pt = parent_action.parse_type()

            parent_action_meta = glob.OBJECT_TYPES[scene.object(
                source_action_pt.obj_id).type].actions[
                    source_action_pt.action_type]

            if len(parent_action.flow(parsed_link.flow_name).outputs) != len(
                    parent_action_meta.returns):
                raise Arcor2Exception(
                    "Source action does not have outputs specified.")

            param_meta = object_action.parameter(param.name)

            try:
                if param_meta.type != parent_action_meta.returns[
                        parsed_link.output_index]:
                    raise Arcor2Exception(
                        "Param type does not match action output type.")
            except IndexError:
                raise Arcor2Exception(
                    f"Index {parsed_link.output_index} is invalid for action {object_action.name},"
                    f" which returns {len(object_action.returns)} values.")

        else:

            if param.type not in known_parameter_types():
                raise Arcor2Exception(
                    f"Parameter {param.name} of action {action.name} has unknown type: {param.type}."
                )

            try:
                plugin_from_type_name(param.type).parameter_value(
                    get_types_dict(), scene, project, action.id, param.name)
            except ParameterPluginException as e:
                raise Arcor2Exception(
                    f"Parameter {param.name} of action {action.name} has invalid value. {str(e)}"
                )
Ejemplo n.º 18
0
    def _add_logic(container: Container,
                   current_action: Action,
                   super_container: Optional[Container] = None) -> None:

        # more paths could lead  to the same action, so it might be already added
        # ...this is easier than searching the tree
        if current_action.id in added_actions:
            logger.debug(
                f"Action {current_action.name} already added, skipping.")
            return

        inputs, outputs = project.action_io(current_action.id)
        logger.debug(
            f"Adding action {current_action.name}, with {len(inputs)} input(s) and {len(outputs)} output(s)."
        )

        act = current_action.parse_type()
        ac_obj = scene.object(act.obj_id).name

        args: List[AST] = []

        # TODO make sure that the order of parameters is correct / re-order
        for param in current_action.parameters:

            if param.type == ActionParameter.TypeEnum.LINK:

                parsed_link = param.parse_link()
                parent_action = project.action(parsed_link.action_id)

                # TODO add support for tuples
                assert len(parent_action.flow(FlowTypes.DEFAULT).outputs
                           ) == 1, "Only one result is supported atm."
                assert parsed_link.output_index == 0

                res_name = parent_action.flow(FlowTypes.DEFAULT).outputs[0]

                # make sure that the result already exists
                if parent_action.id not in added_actions:
                    raise SourceException(
                        f"Action {current_action.name} attempts to use result {res_name} "
                        f"of subsequent action {parent_action.name}.")

                args.append(Name(id=res_name, ctx=Load()))

            elif param.type == ActionParameter.TypeEnum.PROJECT_PARAMETER:
                args.append(
                    Name(id=project.parameter(param.str_from_value()).name,
                         ctx=Load()))
            else:

                plugin = plugin_from_type_name(param.type)

                args.append(
                    plugin.parameter_ast(type_defs, scene, project,
                                         current_action.id, param.name))

                list_of_imp_tup = plugin.need_to_be_imported(
                    type_defs, scene, project, current_action.id, param.name)

                if list_of_imp_tup:
                    # TODO what if there are two same names?
                    for imp_tup in list_of_imp_tup:
                        add_import(tree,
                                   imp_tup.module_name,
                                   imp_tup.class_name,
                                   try_to_import=False)

        add_method_call(
            container.body,
            ac_obj,
            act.action_type,
            args,
            [keyword(arg="an", value=Str(s=current_action.name, kind=""))],
            current_action.flow(FlowTypes.DEFAULT).outputs,
        )

        added_actions.add(current_action.id)

        if not outputs:
            raise SourceException(
                f"Action {current_action.name} has no outputs.")
        elif len(outputs) == 1:
            output = outputs[0]

            if output.end == output.END:
                # TODO this is just temporary (while there is while loop), should be rather Return()
                container.body.append(Continue())
                return

            seq_act = project.action(output.end)
            seq_act_inputs, _ = project.action_io(seq_act.id)
            if len(seq_act_inputs
                   ) > 1:  # the action belongs to a different block

                if seq_act.id in added_actions:
                    return

                logger.debug(
                    f"Action {seq_act.name} going to be added to super_container."
                )

                # test if this is the correct super_container -> count distance (number of blocks) to the START
                blocks_to_start: Dict[str, int] = {}

                for inp in seq_act_inputs:
                    parsed_start = inp.parse_start()
                    pact = project.action(parsed_start.start_action_id)
                    blocks_to_start[pact.id] = _blocks_to_start(pact)
                winner = min(blocks_to_start, key=blocks_to_start.get
                             )  # type: ignore  # TODO what is wrong with it?

                # TODO if blocks_to_start is cached somewhere, the second part of the condition is useless
                # it might happen that there are two different ways with the same distance
                if winner == current_action.id or all(
                        value == list(blocks_to_start.values())[0]
                        for value in blocks_to_start.values()):
                    assert super_container is not None
                    _add_logic(super_container, seq_act)
                return

            logger.debug(f"Sequential action: {seq_act.name}")
            _add_logic(container, seq_act, super_container)

        else:

            root_if: Optional[If] = None

            # action has more outputs - each output should have condition
            for idx, output in enumerate(outputs):
                if not output.condition:
                    raise SourceException("Missing condition.")

                # TODO use parameter plugin (action metadata will be needed - to get the return types)
                # TODO support for other countable types
                # ...this will only work for booleans
                from arcor2 import json

                condition_value = json.loads(output.condition.value)
                comp = NameConstant(value=condition_value, kind=None)
                what = output.condition.parse_what()
                output_name = project.action(what.action_id).flow(
                    what.flow_name).outputs[what.output_index]

                cond = If(
                    test=Compare(left=Name(id=output_name, ctx=Load()),
                                 ops=[Eq()],
                                 comparators=[comp]),
                    body=[],
                    orelse=[],
                )

                if idx == 0:
                    root_if = cond
                    container.body.append(root_if)
                    logger.debug(f"Adding branch for: {condition_value}")
                else:
                    assert isinstance(root_if, If)
                    root_if.orelse.append(cond)

                if output.end == output.END:
                    cond.body.append(
                        Continue())  # TODO should be rather return
                    continue

                _add_logic(cond, project.action(output.end), container)