Beispiel #1
0
def check_override(scene: CachedScene,
                   project: CachedProject,
                   obj_id: str,
                   override: Parameter,
                   add_new_one: bool = False) -> SceneObject:

    obj = scene.object(obj_id)

    for par in glob.OBJECT_TYPES[obj.type].meta.settings:
        if par.name == override.name:
            if par.type != override.type:
                raise Arcor2Exception("Override can't change parameter type.")
            break
    else:
        raise Arcor2Exception("Unknown parameter name.")

    if add_new_one:
        try:
            for existing_override in project.overrides[obj.id]:
                if override.name == existing_override.name:
                    raise Arcor2Exception("Override already exists.")
        except KeyError:
            pass
    else:
        if obj.id not in project.overrides:
            raise Arcor2Exception("There are no overrides for the object.")

        for override in project.overrides[obj.id]:
            if override.name == override.name:
                break
        else:
            raise Arcor2Exception("Override not found.")

    return obj
Beispiel #2
0
def test_obj_relative_ap_global() -> None:

    scene = Scene("s1")
    # object rotated 90° clock-wise
    so1 = SceneObject(
        "so1", "WhatEver",
        Pose(Position(1, 0, 0), Orientation(0, 0, -0.707, 0.707)))
    scene.objects.append(so1)
    cached_scene = CachedScene(scene)

    project = Project("p1", scene.id)
    ap1 = ActionPoint("ap1", Position(1, 0, 0), parent=so1.id)
    project.action_points.append(ap1)
    ap2 = ActionPoint("ap2", Position(1, 0, 0), parent=ap1.id)
    no1 = NamedOrientation("o1", Orientation())
    ap2.orientations.append(no1)
    project.action_points.append(ap2)

    cached_project = CachedProject(project)

    make_relative_ap_global(cached_scene, cached_project, ap2)
    check_ap(ap2)

    assert ap2.position == Position(1, -2, 0)
    assert so1.pose
    assert no1.orientation == so1.pose.orientation

    make_global_ap_relative(cached_scene, cached_project, ap2, ap1.id)

    assert ap2.position == Position(1, 0, 0)
    assert no1.orientation == Orientation()
    check_ap(ap2)
Beispiel #3
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
Beispiel #4
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))
Beispiel #5
0
async def update_scene(scene: CachedScene) -> datetime:

    assert scene.id

    ret = await ps.update_scene(scene.scene)
    scene.modified = ret

    if not scene.created:
        scene.created = scene.modified

    _scenes_list.listing[scene.id] = IdDesc(scene.id, scene.name,
                                            scene.created, scene.modified,
                                            scene.description)
    _scenes[scene.id] = deepcopy(scene)
    _scenes[scene.id].int_modified = None

    return ret
Beispiel #6
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))
Beispiel #7
0
def test_slots() -> None:
    """Tests whether classes from cached module uses __slots__."""

    s = Scene("")
    p = Project("", s.id)

    assert not hasattr(CachedScene(s), "__dict__")
    assert not hasattr(CachedProject(p), "__dict__")
    assert not hasattr(UpdateableCachedScene(s), "__dict__")
    assert not hasattr(UpdateableCachedProject(p), "__dict__")
Beispiel #8
0
def check_ap_parent(scene: CachedScene, proj: CachedProject, parent: Optional[str]) -> None:

    if not parent:
        return

    if parent in scene.object_ids:
        if scene.object(parent).pose is None:
            raise Arcor2Exception("AP can't have object without pose as parent.")
    elif parent not in proj.action_points_ids:
        raise Arcor2Exception("AP has invalid parent ID (not an object or another AP).")
Beispiel #9
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
Beispiel #10
0
def project_problems(obj_types: ObjectTypeDict, scene: CachedScene, project: CachedProject) -> list[str]:

    if project.scene_id != scene.id:
        return ["Project/scene mismatch."]

    problems: list[str] = scene_problems(obj_types, scene)

    for proj_param in project.parameters:
        try:
            check_project_parameter(project, proj_param)
        except Arcor2Exception as e:
            problems.append(str(e))

    for ap in project.action_points:

        try:
            check_ap_parent(scene, project, ap.parent)
        except Arcor2Exception:
            problems.append(f"Action point {ap.name} has invalid parent: {ap.parent}.")

        for joints in project.ap_joints(ap.id):
            if joints.robot_id not in scene.object_ids:
                problems.append(
                    f"Action point {ap.name} has joints ({joints.name}) for an unknown robot: {joints.robot_id}."
                )

        for action in project.actions:

            # check if objects have used actions
            obj_id, action_type = action.parse_type()

            if obj_id not in scene.object_ids:
                problems.append(f"Object ID {obj_id} which action is used in {action.name} does not exist in scene.")
                continue

            scene_obj = scene.object(obj_id)
            if action_type not in obj_types[scene_obj.type].actions:
                problems.append(
                    f"ObjectType {scene_obj.type} does not have action {action_type} used in {action.name}."
                )
                continue

            action_meta = obj_types[scene_obj.type].actions[action_type]

            try:
                check_action_params(obj_types, scene, project, action, action_meta)
            except Arcor2Exception as e:
                problems.append(str(e))

            try:
                check_flows(project, action, action_meta)
            except Arcor2Exception as e:
                problems.append(str(e))

    return problems
Beispiel #11
0
def patch_with_action_mapping(type_def: type[Generic], scene: CachedScene,
                              project: CachedProject) -> None:

    setattr(
        type_def,
        ACTION_NAME_ID_MAPPING_ATTR,
        {
            act.name: act.id
            for act in project.actions
            if scene.object(act.parse_type().obj_id).type == type_def.__name__
        },
    )
Beispiel #12
0
async def get_scene(scene_id: str) -> CachedScene:

    async with _scenes_list_lock:
        try:
            scene = _scenes[scene_id]
            assert scene.modified
        except KeyError:
            scene = CachedScene(await ps.get_scene(scene_id))
            _scenes[scene_id] = scene
        else:
            await _update_list(ps.get_scenes, _scenes_list, _scenes)

            if scene_id not in _scenes_list.listing:
                _scenes.pop(scene_id, None)
                raise Arcor2Exception("Scene removed externally.")

            # scene in cache is outdated
            if scene.modified < _scenes_list.listing[scene_id].modified:
                scene = CachedScene(await ps.get_scene(scene_id))
                _scenes[scene_id] = scene

    return scene
Beispiel #13
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
Beispiel #14
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
Beispiel #15
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
Beispiel #16
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
Beispiel #17
0
def test_make_relative_ap_global_and_relative_again() -> None:

    scene = Scene("s1")
    so1 = SceneObject("so1", "WhatEver", Pose(Position(3, 0, 0),
                                              Orientation()))
    scene.objects.append(so1)
    cached_scene = CachedScene(scene)

    project = Project("p1", scene.id)
    ap1 = ActionPoint("ap1", Position(-1, 0, 0), parent=so1.id)
    project.action_points.append(ap1)
    ap2 = ActionPoint("ap2", Position(-1, 0, 0), parent=ap1.id)
    project.action_points.append(ap2)
    ap3 = ActionPoint(
        "ap3",
        Position(-1, 0, 0),
        parent=ap2.id,
        orientations=[NamedOrientation("bla", random_orientation())])
    project.action_points.append(ap3)

    cached_project = CachedProject(project)

    assert ap3.parent
    ap3_parent = get_parent_pose(cached_scene, cached_project, ap3.parent)

    assert Pose(ap2.position, Orientation()) == ap3_parent.pose
    assert ap3_parent.parent_id == ap1.id

    make_relative_ap_global(cached_scene, cached_project, ap3)

    check_ap(ap3)

    assert ap3.parent is None
    assert ap3.position.x == 0.0  # type: ignore

    make_global_ap_relative(cached_scene, cached_project, ap3, ap2.id)

    check_ap(ap3)

    assert ap3.parent == ap2.id
    assert ap3.position.x == -1

    ap3.parent = "something_unknown"

    with pytest.raises(Arcor2Exception):
        make_relative_ap_global(cached_scene, cached_project, ap3)
Beispiel #18
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
Beispiel #19
0
async def project_info(
        project_id: str, scenes_lock: asyncio.Lock,
        scenes: Dict[str, CachedScene]) -> srpc.p.ListProjects.Response.Data:

    project = await storage.get_project(project_id)

    assert project.modified is not None

    pd = srpc.p.ListProjects.Response.Data(id=project.id,
                                           desc=project.desc,
                                           name=project.name,
                                           scene_id=project.scene_id,
                                           modified=project.modified)

    try:
        cached_project = UpdateableCachedProject(project)
    except CachedProjectException as e:
        pd.problems.append(str(e))
        return pd

    try:
        async with scenes_lock:
            if project.scene_id not in scenes:
                scenes[project.scene_id] = CachedScene(await storage.get_scene(
                    project.scene_id))
    except storage.ProjectServiceException:
        pd.problems.append("Scene does not exist.")
        return pd

    pd.problems = project_problems(scenes[project.scene_id], cached_project)
    pd.valid = not pd.problems

    if not pd.valid:
        return pd

    try:
        # TODO call build service!!!
        pd.executable = True
    except Arcor2Exception as e:
        pd.problems.append(str(e))

    return pd
Beispiel #20
0
def get_parent_pose(scene: CScene, project: CProject, parent_id: str) -> Parent:
    """Returns pose of the parent and parent of the parent (if any).

    :param scene:
    :param project:
    :param parent_id:
    :return:
    """

    if parent_id in scene.object_ids:
        parent_obj = scene.object(parent_id)
        if not parent_obj.pose:
            raise Arcor2Exception("Parent object does not have pose!")
        # TODO find parent object in the graph (SceneObject has "children" property)
        return Parent(parent_obj.pose, None)
    elif parent_id in project.action_points_ids:
        ap = project.bare_action_point(parent_id)
        return Parent(Pose(ap.position, Orientation()), ap.parent)
    else:
        raise Arcor2Exception(f"Unknown parent_id {parent_id}.")
Beispiel #21
0
def check_object(scene: CachedScene,
                 obj: SceneObject,
                 new_one: bool = False) -> None:
    """Checks if object can be added into the scene."""

    assert not obj.children

    if obj.type not in glob.OBJECT_TYPES:
        raise Arcor2Exception("Unknown object type.")

    obj_type = glob.OBJECT_TYPES[obj.type]

    if obj_type.meta.disabled:
        raise Arcor2Exception("Object type disabled.")

    check_object_parameters(obj_type, obj.parameters)

    # TODO check whether object needs parent and if so, if the parent is in scene and parent_id is set
    if obj_type.meta.needs_parent_type:
        pass

    if obj_type.meta.has_pose and obj.pose is None:
        raise Arcor2Exception("Object requires pose.")

    if not obj_type.meta.has_pose and obj.pose is not None:
        raise Arcor2Exception("Object do not have pose.")

    if obj_type.meta.abstract:
        raise Arcor2Exception("Cannot instantiate abstract type.")

    if new_one:

        if obj.id in scene.object_ids:
            raise Arcor2Exception(
                "Object/service with that id already exists.")

        if obj.name in scene.object_names():
            raise Arcor2Exception("Name is already used.")

    hlp.is_valid_identifier(obj.name)
Beispiel #22
0
    def parameter_value(cls, type_defs: TypesDict, scene: CScene,
                        project: CProject, action_id: str,
                        parameter_id: str) -> Enum:

        action = project.action(action_id)
        param = action.parameter(parameter_id)
        obj_id, action_type = action.parse_type()
        obj_type_name = scene.object(obj_id).type
        try:
            obj_type = type_defs[obj_type_name]
        except KeyError:
            raise ParameterPluginException(
                f"Unknown object type {obj_type_name}.")

        try:
            method = getattr(obj_type, action_type)
        except AttributeError:
            raise ParameterPluginException(
                f"Object type {obj_type_name} does not have method {action_type}."
            )

        try:
            ttype = get_type_hints(method)[param.name]
        except KeyError:
            raise ParameterPluginException(
                f"Method {obj_type}/{method.__name__} does not have parameter {param.name}."
            )

        if not issubclass(ttype, cls.type()):
            raise ParameterPluginException(
                f"Type {ttype.__name__} is not subclass of {cls.type().__name__}."
            )

        try:
            return ttype(json.loads(param.value))
        except ValueError:
            raise ParameterPluginException(
                f"Parameter {parameter_id} of action {action.name} has invalid value."
            )
Beispiel #23
0
def check_object(obj_types: ObjectTypeDict, scene: CachedScene, obj: SceneObject, new_one: bool = False) -> None:
    """Checks if object can be added into the scene."""

    assert not obj.children

    if obj.type not in obj_types:
        raise Arcor2Exception(f"Unknown ObjectType {obj.type}.")

    obj_type = obj_types[obj.type]

    if obj_type.meta.disabled:
        raise Arcor2Exception(f"ObjectType {obj.type} is disabled. {obj_type.meta.problem}")

    check_object_parameters(obj_type, obj.parameters)

    # TODO check whether object needs parent and if so, if the parent is in scene and parent_id is set
    if obj_type.meta.needs_parent_type:
        pass

    if obj_type.meta.has_pose and obj.pose is None:
        raise Arcor2Exception(f"Object {obj.name} requires pose.")

    if not obj_type.meta.has_pose and obj.pose is not None:
        raise Arcor2Exception(f"Object {obj.name} should not have pose.")

    if obj_type.meta.abstract:
        raise Arcor2Exception(f"ObjectType {obj.type} is abstract.")

    if new_one:

        if obj.id in scene.object_ids:
            raise Arcor2Exception(f"Object {obj.name} has duplicate id.")

        if obj.name in scene.object_names():
            raise Arcor2Exception(f"Object name {obj.name} is duplicate.")

    hlp.is_valid_identifier(obj.name)
Beispiel #24
0
def _publish(project_id: str, package_name: str) -> RespT:

    mem_zip = BytesIO()

    logger.debug(
        f"Generating package {package_name} for project_id: {project_id}.")

    types_dict: TypesDict = {}

    # restore original environment
    sys.path = list(original_sys_path)
    sys.modules = dict(original_sys_modules)

    with tempfile.TemporaryDirectory() as tmp_dir:

        prepare_object_types_dir(tmp_dir, OBJECT_TYPE_MODULE)

        with zipfile.ZipFile(mem_zip,
                             mode="w",
                             compression=zipfile.ZIP_DEFLATED) as zf:

            try:
                logger.debug("Getting scene and project.")
                project = ps.get_project(project_id)
                cached_project = CachedProject(project)
                scene = ps.get_scene(project.scene_id)
                cached_scene = CachedScene(scene)

                if not package_name:
                    package_name = project.name

                data_path = "data"
                ot_path = "object_types"

                zf.writestr(os.path.join(ot_path, "__init__.py"), "")
                zf.writestr(os.path.join(data_path, "project.json"),
                            project.to_json())
                zf.writestr(os.path.join(data_path, "scene.json"),
                            scene.to_json())

                obj_types = set(cached_scene.object_types)
                obj_types_with_models: set[str] = set()

                if __debug__:  # this should uncover potential problems with order in which ObjectTypes are processed
                    import random

                    random.shuffle(scene.objects)

                for scene_obj in scene.objects:

                    if scene_obj.type in types_dict:
                        continue

                    logger.debug(
                        f"Getting scene object type {scene_obj.type}.")
                    obj_type = ps.get_object_type(scene_obj.type)

                    if obj_type.model and obj_type.id not in obj_types_with_models:
                        obj_types_with_models.add(obj_type.id)

                        model = ps.get_model(obj_type.model.id,
                                             obj_type.model.type)
                        obj_model = ObjectModel(
                            obj_type.model.type,
                            **{model.type().value.lower():
                               model}  # type: ignore
                        )

                        zf.writestr(
                            os.path.join(
                                data_path, "models",
                                humps.depascalize(obj_type.id) + ".json"),
                            obj_model.to_json(),
                        )

                    zf.writestr(
                        os.path.join(ot_path, humps.depascalize(obj_type.id)) +
                        ".py", obj_type.source)

                    # handle inheritance
                    get_base_from_project_service(types_dict, tmp_dir,
                                                  obj_types, obj_type, zf,
                                                  ot_path,
                                                  parse(obj_type.source))

                    types_dict[scene_obj.type] = save_and_import_type_def(
                        obj_type.source, scene_obj.type, Generic, tmp_dir,
                        OBJECT_TYPE_MODULE)

            except Arcor2Exception as e:
                logger.exception(
                    f"Failed to prepare package content. {str(e)}")
                raise FlaskException(str(e), error_code=404)

            script_path = "script.py"

            try:

                if project.has_logic:
                    logger.debug("Generating script from project logic.")
                    zf.writestr(
                        script_path,
                        program_src(types_dict, cached_project, cached_scene,
                                    True))
                else:
                    try:
                        logger.debug("Getting project sources.")
                        script = ps.get_project_sources(project.id).script

                        # check if it is a valid Python code
                        try:
                            parse(script)
                        except SourceException:
                            logger.exception(
                                "Failed to parse code of the uploaded script.")
                            raise FlaskException("Invalid code.",
                                                 error_code=501)

                        zf.writestr(script_path, script)

                    except ps.ProjectServiceException:

                        logger.info(
                            "Script not found on project service, creating one from scratch."
                        )

                        # write script without the main loop
                        zf.writestr(
                            script_path,
                            program_src(types_dict, cached_project,
                                        cached_scene, False))

                logger.debug("Generating supplementary files.")

                logger.debug("action_points.py")
                zf.writestr("action_points.py",
                            global_action_points_class(cached_project))

                logger.debug("package.json")
                zf.writestr(
                    "package.json",
                    PackageMeta(package_name,
                                datetime.now(tz=timezone.utc)).to_json())

            except Arcor2Exception as e:
                logger.exception("Failed to generate script.")
                raise FlaskException(str(e), error_code=501)

    logger.info(
        f"Done with {package_name} (scene {scene.name}, project {project.name})."
    )
    mem_zip.seek(0)

    return send_file(mem_zip,
                     as_attachment=True,
                     max_age=0,
                     download_name=f"{package_name}_package.zip")
Beispiel #25
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
Beispiel #26
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)}"
                )
Beispiel #27
0
async def scenes() -> AsyncIterator[CachedScene]:

    for scene_id in await storage.get_scene_ids():
        yield CachedScene(await storage.get_scene(scene_id))
Beispiel #28
0
def check_scene_for_object_type(scene: CachedScene, object_type: str) -> None:

    for _ in scene.objects_of_type(object_type):
        raise Arcor2Exception(f"Object type used in scene {scene.name}.")
Beispiel #29
0
def get_obj_type_data(scene: CachedScene, object_id: str) -> ObjectTypeData:

    try:
        return glob.OBJECT_TYPES[scene.object(object_id).type]
    except KeyError:
        raise Arcor2Exception("Unknown object type.")
Beispiel #30
0
def get_obj_type_data(scene: CachedScene, object_id: str) -> ObjectTypeData:
    return glob.OBJECT_TYPES[scene.object(object_id).type]