Exemple #1
0
def test_object_actions() -> None:

    actions = object_actions(TestObject, parse_def(TestObject))
    assert len(actions) == 2

    for act in actions.values():

        if act.name == TestObject.action_1.__name__:

            expected_meta = ActionMetadata(blocking=True)
            expected_meta.cancellable = True
            assert act.meta == expected_meta
            assert not act.returns
            assert act.description == "Short description."
            assert not act.disabled
            assert act.origins is None
            assert len(act.parameters) == 3

            for param in act.parameters:
                if param.name == "param1":
                    assert param.description == "str param"
                elif param.name == "param2":
                    assert param.description == "int param"
                elif param.name == "param3":
                    assert param.description == "bool param"
                else:
                    pytest.fail(
                        f"Unknown parameter: {param.name} of action {act.name}."
                    )

        elif act.name == TestObject.action_2.__name__:

            assert act.meta == ActionMetadata()
            assert len(act.returns) == 1
            assert act.description == "Short description"
            assert not act.disabled
            assert act.origins is None
            assert not act.parameters
        else:
            pytest.fail(f"Unknown action: {act.name}.")
Exemple #2
0
async def new_object_type_cb(req: srpc.o.NewObjectType.Request,
                             ui: WsClient) -> None:

    async with ctx_write_lock(glob.LOCK.SpecialValues.ADDING_OBJECT, ui):
        meta = req.args

        if meta.type in glob.OBJECT_TYPES:
            raise Arcor2Exception("Object type already exists.")

        hlp.is_valid_type(meta.type)

        if meta.base not in glob.OBJECT_TYPES:
            raise Arcor2Exception(
                f"Unknown base object type '{meta.base}', "
                f"known types are: {', '.join(glob.OBJECT_TYPES.keys())}.")

        base = glob.OBJECT_TYPES[meta.base]

        if base.meta.disabled:
            raise Arcor2Exception("Base object is disabled.")

        assert base.type_def is not None

        if issubclass(base.type_def, Robot):
            raise Arcor2Exception("Can't subclass Robot.")

        meta.has_pose = issubclass(base.type_def, GenericWithPose)

        if not meta.has_pose and meta.object_model:
            raise Arcor2Exception(
                "Object without pose can't have collision model.")

        if req.dry_run:
            return None

        obj = meta.to_object_type()
        ast = new_object_type(glob.OBJECT_TYPES[meta.base].meta, meta)
        obj.source = tree_to_str(ast)

        if meta.object_model:

            if meta.object_model.type == Model3dType.MESH:

                # TODO check whether mesh id exists - if so, then use existing mesh, if not, upload a new one
                # ...get whole mesh (focus_points) based on mesh id
                assert meta.object_model.mesh
                try:
                    meta.object_model.mesh = await storage.get_mesh(
                        meta.object_model.mesh.id)
                except storage.ProjectServiceException as e:
                    glob.logger.error(e)
                    raise Arcor2Exception(
                        f"Mesh ID {meta.object_model.mesh.id} does not exist.")

            else:

                meta.object_model.model().id = meta.type
                await storage.put_model(meta.object_model.model())

        type_def = await hlp.run_in_executor(
            hlp.save_and_import_type_def,
            obj.source,
            obj.id,
            base.type_def,
            settings.OBJECT_TYPE_PATH,
            settings.OBJECT_TYPE_MODULE,
        )
        assert issubclass(type_def, base.type_def)
        actions = object_actions(type_def, ast)

        await storage.update_object_type(obj)

        glob.OBJECT_TYPES[meta.type] = ObjectTypeData(meta, type_def, actions,
                                                      ast)
        add_ancestor_actions(meta.type, glob.OBJECT_TYPES)

        evt = sevts.o.ChangedObjectTypes([meta])
        evt.change_type = events.Event.Type.ADD
        asyncio.ensure_future(notif.broadcast_event(evt))
        return None
Exemple #3
0
async def get_object_data(object_types: ObjectTypeDict, obj_id: str) -> None:

    logger.debug(f"Processing {obj_id}.")

    if obj_id in object_types:
        logger.debug(f"{obj_id} already processed, skipping...")
        return

    obj_iddesc = await storage.get_object_type_iddesc(obj_id)

    if obj_id in glob.OBJECT_TYPES:

        assert obj_iddesc.modified
        assert glob.OBJECT_TYPES[
            obj_id].meta.modified, f"Object {obj_id} does not have 'modified' in its meta."

        if obj_iddesc.modified == glob.OBJECT_TYPES[obj_id].meta.modified:
            logger.debug(f"No need to update {obj_id}.")
            return

    obj = await storage.get_object_type(obj_id)

    try:
        bases = otu.base_from_source(obj.source, obj_id)

        if not bases:
            logger.debug(
                f"{obj_id} is definitely not an ObjectType (subclass of {object.__name__}), maybe mixin?"
            )
            return

        if bases[0] not in object_types.keys() | built_in_types_names():
            logger.debug(f"Getting base class {bases[0]} for {obj_id}.")
            await get_object_data(object_types, bases[0])

        for mixin in bases[1:]:
            mixin_obj = await storage.get_object_type(mixin)

            await hlp.run_in_executor(
                hlp.save_and_import_type_def,
                mixin_obj.source,
                mixin_obj.id,
                object,
                settings.OBJECT_TYPE_PATH,
                settings.OBJECT_TYPE_MODULE,
            )

    except Arcor2Exception as e:
        logger.error(
            f"Disabling ObjectType {obj.id}: can't get a base. {str(e)}")
        object_types[obj_id] = ObjectTypeData(
            ObjectTypeMeta(obj_id,
                           "ObjectType disabled.",
                           disabled=True,
                           problem="Can't get base.",
                           modified=obj.modified))
        return

    logger.debug(f"Updating {obj_id}.")

    try:
        type_def = await hlp.run_in_executor(
            hlp.save_and_import_type_def,
            obj.source,
            obj.id,
            Generic,
            settings.OBJECT_TYPE_PATH,
            settings.OBJECT_TYPE_MODULE,
        )
    except Arcor2Exception as e:
        logger.debug(f"{obj.id} is probably not an ObjectType. {str(e)}")
        return

    assert issubclass(type_def, Generic)

    try:
        meta = meta_from_def(type_def)
    except Arcor2Exception as e:
        logger.error(f"Disabling ObjectType {obj.id}.")
        logger.debug(e, exc_info=True)
        object_types[obj_id] = ObjectTypeData(
            ObjectTypeMeta(obj_id,
                           "ObjectType disabled.",
                           disabled=True,
                           problem=str(e),
                           modified=obj.modified))
        return

    meta.modified = obj.modified

    if obj.model:
        try:
            model = await storage.get_model(obj.model.id, obj.model.type)
        except Arcor2Exception as e:
            logger.error(
                f"{obj.model.id}: failed to get collision model of type {obj.model.type}. {str(e)}"
            )
            meta.disabled = True
            meta.problem = "Can't get collision model."
            object_types[obj_id] = ObjectTypeData(meta)
            return

        if isinstance(model,
                      Mesh) and model.data_id not in await storage.files_ids():
            logger.error(
                f"Disabling {meta.type} as its mesh file {model.data_id} does not exist."
            )
            meta.disabled = True
            meta.problem = "Mesh file does not exist."
            object_types[obj_id] = ObjectTypeData(meta)
            return

        kwargs = {model.type().value.lower(): model}
        meta.object_model = ObjectModel(model.type(), **kwargs)  # type: ignore

    ast = parse(obj.source)
    otd = ObjectTypeData(meta, type_def, object_actions(type_def, ast), ast)

    object_types[obj_id] = otd
Exemple #4
0
async def get_object_data(object_types: ObjectTypeDict, obj_id: str) -> None:

    glob.logger.debug(f"Processing {obj_id}.")

    if obj_id in object_types:
        glob.logger.debug(f"{obj_id} already processed, skipping...")
        return

    obj = await storage.get_object_type(obj_id)

    if obj_id in glob.OBJECT_TYPES and glob.OBJECT_TYPES[obj_id].type_def is not None:

        stored_type_def = glob.OBJECT_TYPES[obj_id].type_def
        assert stored_type_def

        # TODO do not compare sources but 'modified`
        # the code we get from type_def has Unix line endings, while the code from Project service might have Windows...
        obj.source = convert_line_endings_to_unix(obj.source)

        if get_containing_module_sources(stored_type_def) == obj.source:
            glob.logger.debug(f"No need to update {obj_id}.")
            return

    try:
        bases = otu.base_from_source(obj.source, obj_id)
        if bases and bases[0] not in object_types.keys() | built_in_types_names():
            glob.logger.debug(f"Getting base class {bases[0]} for {obj_id}.")
            await get_object_data(object_types, bases[0])

        for mixin in bases[1:]:
            mixin_obj = await storage.get_object_type(mixin)

            await hlp.run_in_executor(
                hlp.save_and_import_type_def,
                mixin_obj.source,
                mixin_obj.id,
                object,
                settings.OBJECT_TYPE_PATH,
                settings.OBJECT_TYPE_MODULE,
            )

    except Arcor2Exception as e:
        glob.logger.warn(f"Disabling object type {obj.id}: can't get a base. {str(e)}")
        object_types[obj_id] = ObjectTypeData(
            ObjectTypeMeta(obj_id, "Object type disabled.", disabled=True, problem="Can't get base.")
        )
        return

    glob.logger.debug(f"Updating {obj_id}.")

    try:
        type_def = await hlp.run_in_executor(
            hlp.save_and_import_type_def,
            obj.source,
            obj.id,
            Generic,
            settings.OBJECT_TYPE_PATH,
            settings.OBJECT_TYPE_MODULE,
        )
    except Arcor2Exception as e:
        glob.logger.debug(f"{obj.id} is probably not an object type. {str(e)}")
        return

    assert issubclass(type_def, Generic)

    try:
        meta = meta_from_def(type_def)
        otu.get_settings_def(type_def)  # just to check if settings are ok
    except Arcor2Exception as e:
        glob.logger.warning(f"Disabling object type {obj.id}.")
        glob.logger.debug(e, exc_info=True)
        object_types[obj_id] = ObjectTypeData(
            ObjectTypeMeta(obj_id, "Object type disabled.", disabled=True, problem=str(e))
        )
        return

    if obj.model:
        try:
            model = await storage.get_model(obj.model.id, obj.model.type)
        except Arcor2Exception:
            glob.logger.error(f"{obj.model.id}: failed to get collision model of type {obj.model.type}.")
            meta.disabled = True
            meta.problem = "Can't get collision model."
            object_types[obj_id] = ObjectTypeData(meta)
            return

        kwargs = {model.type().value.lower(): model}
        meta.object_model = ObjectModel(model.type(), **kwargs)  # type: ignore

    ast = parse(obj.source)
    otd = ObjectTypeData(meta, type_def, object_actions(type_def, ast), ast)

    object_types[obj_id] = otd
Exemple #5
0
async def get_object_data(object_types: ObjectTypeDict, obj_id: str) -> None:

    glob.logger.debug(f"Processing {obj_id}.")

    if obj_id in object_types:
        glob.logger.debug(f"{obj_id} already processed, skipping...")
        return

    obj = await storage.get_object_type(obj_id)

    if obj_id in glob.OBJECT_TYPES and glob.OBJECT_TYPES[
            obj_id].type_def is not None:

        stored_type_def = glob.OBJECT_TYPES[obj_id].type_def
        assert stored_type_def
        if hash(get_containing_module_sources(stored_type_def)) == hash(
                obj.source):
            glob.logger.debug(f"No need to update {obj_id}.")
            return

    try:
        base = otu.base_from_source(obj.source, obj_id)
        if base and base not in object_types.keys() | built_in_types_names():
            glob.logger.debug(f"Getting base class {base} for {obj_id}.")
            await get_object_data(object_types, base)
    except Arcor2Exception:
        object_types[obj_id] = ObjectTypeData(
            ObjectTypeMeta(obj_id,
                           "Object type disabled.",
                           disabled=True,
                           problem="Can't get base."))
        return

    glob.logger.debug(f"Updating {obj_id}.")

    try:
        type_def = await hlp.run_in_executor(
            hlp.save_and_import_type_def,
            obj.source,
            obj.id,
            Generic,
            settings.OBJECT_TYPE_PATH,
            settings.OBJECT_TYPE_MODULE,
        )
        assert issubclass(type_def, Generic)
        meta = meta_from_def(type_def)
        otu.get_settings_def(type_def)  # just to check if settings are ok
    except Arcor2Exception as e:
        glob.logger.warning(f"Disabling object type {obj.id}.")
        glob.logger.debug(e, exc_info=True)
        object_types[obj_id] = ObjectTypeData(
            ObjectTypeMeta(obj_id,
                           "Object type disabled.",
                           disabled=True,
                           problem=str(e)))
        return

    if obj.model:
        try:
            model = await storage.get_model(obj.model.id, obj.model.type)
        except Arcor2Exception:
            glob.logger.error(
                f"{obj.model.id}: failed to get collision model of type {obj.model.type}."
            )
            meta.disabled = True
            meta.problem = "Can't get collision model."
            object_types[obj_id] = ObjectTypeData(meta)
            return

        kwargs = {model.type().value.lower(): model}
        meta.object_model = ObjectModel(model.type(), **kwargs)  # type: ignore

    ast = parse(obj.source)
    otd = ObjectTypeData(meta, type_def, object_actions(type_def, ast), ast)

    object_types[obj_id] = otd
Exemple #6
0
async def new_object_type_cb(req: srpc.o.NewObjectType.Request,
                             ui: WsClient) -> None:

    async with ctx_write_lock(glob.LOCK.SpecialValues.ADDING_OBJECT,
                              glob.USERS.user_name(ui)):
        meta = req.args

        if meta.type in glob.OBJECT_TYPES:
            raise Arcor2Exception("Object type already exists.")

        hlp.is_valid_type(meta.type)

        if meta.base not in glob.OBJECT_TYPES:
            raise Arcor2Exception(
                f"Unknown base object type '{meta.base}', "
                f"known types are: {', '.join(glob.OBJECT_TYPES.keys())}.")

        base = glob.OBJECT_TYPES[meta.base]

        if base.meta.disabled:
            raise Arcor2Exception("Base object is disabled.")

        assert base.type_def is not None

        if issubclass(base.type_def, Robot):
            raise Arcor2Exception("Can't subclass Robot.")

        meta.has_pose = issubclass(base.type_def, GenericWithPose)

        if issubclass(base.type_def, CollisionObject):
            if not meta.object_model:
                raise Arcor2Exception(
                    "Objects based on CollisionObject must have collision model."
                )
        else:
            if meta.object_model:
                raise Arcor2Exception(
                    "Only objects based on CollisionObject can have collision model."
                )

        if req.dry_run:
            return None

        obj = meta.to_object_type()
        ast = new_object_type(glob.OBJECT_TYPES[meta.base].meta, meta)
        obj.source = tree_to_str(ast)

        if meta.object_model:
            await update_object_model(meta, meta.object_model)

        type_def = await hlp.run_in_executor(
            hlp.save_and_import_type_def,
            obj.source,
            obj.id,
            base.type_def,
            settings.OBJECT_TYPE_PATH,
            settings.OBJECT_TYPE_MODULE,
        )
        assert issubclass(type_def, base.type_def)
        actions = object_actions(type_def, ast)

        meta.modified = await storage.update_object_type(obj)

        glob.OBJECT_TYPES[meta.type] = ObjectTypeData(meta, type_def, actions,
                                                      ast)
        add_ancestor_actions(meta.type, glob.OBJECT_TYPES)

        evt = sevts.o.ChangedObjectTypes([meta])
        evt.change_type = events.Event.Type.ADD
        asyncio.ensure_future(notif.broadcast_event(evt))
        return None