コード例 #1
0
ファイル: objects_actions.py プロジェクト: ZdenekM/arcor2
async def get_object_types() -> UpdatedObjectTypes:
    """Serves to initialize or update knowledge about awailable ObjectTypes.

    :return:
    """

    initialization = False

    # initialize with built-in types, this has to be done just once
    if not glob.OBJECT_TYPES:
        logger.debug("Initialization of ObjectTypes.")
        initialization = True
        await hlp.run_in_executor(prepare_object_types_dir,
                                  settings.OBJECT_TYPE_PATH,
                                  settings.OBJECT_TYPE_MODULE)
        glob.OBJECT_TYPES.update(built_in_types_data())

    updated_object_types: ObjectTypeDict = {}

    object_type_ids: Union[set[str],
                           list[str]] = await storage.get_object_type_ids()

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

        object_type_ids = list(object_type_ids)
        random.shuffle(object_type_ids)

    for obj_id in object_type_ids:
        await get_object_data(updated_object_types, obj_id)

    removed_object_ids = {
        obj
        for obj in glob.OBJECT_TYPES.keys() if obj not in object_type_ids
    } - built_in_types_names()
    updated_object_ids = {
        k
        for k in updated_object_types.keys() if k in glob.OBJECT_TYPES
    }
    new_object_ids = {
        k
        for k in updated_object_types.keys() if k not in glob.OBJECT_TYPES
    }

    logger.debug(f"Removed ids: {removed_object_ids}")
    logger.debug(f"Updated ids: {updated_object_ids}")
    logger.debug(f"New ids: {new_object_ids}")

    if not initialization and removed_object_ids:

        # TODO remove it from sys.modules

        remove_evt = ChangedObjectTypes([
            v.meta for k, v in glob.OBJECT_TYPES.items()
            if k in removed_object_ids
        ])
        remove_evt.change_type = Event.Type.REMOVE
        asyncio.ensure_future(notif.broadcast_event(remove_evt))

        for removed in removed_object_ids:
            assert removed not in built_in_types_names(
            ), "Attempt to remove built-in type."
            del glob.OBJECT_TYPES[removed]
            await hlp.run_in_executor(remove_object_type, removed)

    glob.OBJECT_TYPES.update(updated_object_types)

    logger.debug(f"All known ids: {glob.OBJECT_TYPES.keys()}")

    for obj_type in updated_object_types.values():

        # if description is missing, try to get it from ancestor(s)
        if not obj_type.meta.description:

            try:
                obj_type.meta.description = obj_description_from_base(
                    glob.OBJECT_TYPES, obj_type.meta)
            except otu.DataError as e:
                logger.error(
                    f"Failed to get info from base for {obj_type}, error: '{e}'."
                )

        if not obj_type.meta.disabled and not obj_type.meta.built_in:
            add_ancestor_actions(obj_type.meta.type, glob.OBJECT_TYPES)

    if not initialization:

        if updated_object_ids:
            update_evt = ChangedObjectTypes([
                v.meta for k, v in glob.OBJECT_TYPES.items()
                if k in updated_object_ids
            ])
            update_evt.change_type = Event.Type.UPDATE
            asyncio.ensure_future(notif.broadcast_event(update_evt))

        if new_object_ids:
            add_evt = ChangedObjectTypes([
                v.meta for k, v in glob.OBJECT_TYPES.items()
                if k in new_object_ids
            ])
            add_evt.change_type = Event.Type.ADD
            asyncio.ensure_future(notif.broadcast_event(add_evt))

    for obj_type in updated_object_types.values():

        if obj_type.type_def and issubclass(
                obj_type.type_def, Robot) and not obj_type.type_def.abstract():
            await get_robot_meta(obj_type)

    # if object does not change but its base has changed, it has to be reloaded
    for obj_id, obj in glob.OBJECT_TYPES.items():

        if obj_id in updated_object_ids:
            continue

        if obj.type_def and obj.meta.base in updated_object_ids:

            logger.debug(
                f"Re-importing {obj.meta.type} because its base {obj.meta.base} type has changed."
            )
            obj.type_def = await hlp.run_in_executor(
                hlp.import_type_def,
                obj.meta.type,
                Generic,
                settings.OBJECT_TYPE_PATH,
                settings.OBJECT_TYPE_MODULE,
            )

    return UpdatedObjectTypes(new_object_ids, updated_object_ids,
                              removed_object_ids)
コード例 #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
コード例 #3
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