async def rename_object_cb(req: srpc.s.RenameObject.Request, ui: WsClient) -> None: scene = glob.LOCK.scene_or_exception(ensure_project_closed=True) target_obj = scene.object(req.args.id) if target_obj.name == req.args.new_name: raise Arcor2Exception("Name unchanged") for obj_name in scene.object_names(): if obj_name == req.args.new_name: raise Arcor2Exception("Object name already exists.") hlp.is_valid_identifier(req.args.new_name) user_name = glob.USERS.user_name(ui) await ensure_locked(req.args.id, ui) if req.dry_run: return None target_obj.name = req.args.new_name scene.update_modified() evt = sevts.s.SceneObjectChanged(target_obj) evt.change_type = Event.Type.UPDATE asyncio.ensure_future(notif.broadcast_event(evt)) asyncio.create_task(glob.LOCK.write_unlock(req.args.id, user_name, True)) return None
async def add_action_point_orientation_cb( req: srpc.p.AddActionPointOrientation.Request, ui: WsClient) -> None: """Adds orientation and joints to the action point. :param req: :return: """ assert glob.SCENE assert glob.PROJECT ap = glob.PROJECT.bare_action_point(req.args.action_point_id) hlp.is_valid_identifier(req.args.name) unique_name(req.args.name, glob.PROJECT.ap_orientation_names(ap.id)) if req.dry_run: return None orientation = common.NamedOrientation(req.args.name, req.args.orientation) glob.PROJECT.upsert_orientation(ap.id, orientation) evt = sevts.p.OrientationChanged(orientation) evt.change_type = Event.Type.ADD evt.parent_id = ap.id asyncio.ensure_future(notif.broadcast_event(evt)) return None
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.")
async def rename_object_cb(req: srpc.s.RenameObject.Request, ui: WsClient) -> None: assert glob.SCENE target_obj = glob.SCENE.object(req.args.id) if target_obj.name == req.args.new_name: return for obj_name in glob.SCENE.object_names(): if obj_name == req.args.new_name: raise Arcor2Exception("Object name already exists.") hlp.is_valid_identifier(req.args.new_name) if req.dry_run: return None target_obj.name = req.args.new_name glob.SCENE.update_modified() evt = sevts.s.SceneObjectChanged(target_obj) evt.change_type = Event.Type.UPDATE asyncio.ensure_future(notif.broadcast_event(evt)) return None
async def add_action_point_joints_using_robot_cb( req: srpc.p.AddActionPointJointsUsingRobot.Request, ui: WsClient) -> None: ensure_scene_started() assert glob.SCENE assert glob.PROJECT ap = glob.PROJECT.bare_action_point(req.args.action_point_id) hlp.is_valid_identifier(req.args.name) unique_name(req.args.name, glob.PROJECT.ap_joint_names(ap.id)) new_joints = await get_robot_joints(req.args.robot_id) if req.dry_run: return None prj = common.ProjectRobotJoints(req.args.name, req.args.robot_id, new_joints, True) glob.PROJECT.upsert_joints(ap.id, prj) evt = sevts.p.JointsChanged(prj) evt.change_type = Event.Type.ADD evt.parent_id = ap.id asyncio.ensure_future(notif.broadcast_event(evt)) return None
async def rename_action_point_cb(req: srpc.p.RenameActionPoint.Request, ui: WsClient) -> None: assert glob.SCENE assert glob.PROJECT ap = glob.PROJECT.bare_action_point(req.args.action_point_id) if req.args.new_name == ap.name: return None hlp.is_valid_identifier(req.args.new_name) unique_name(req.args.new_name, glob.PROJECT.action_points_names) if req.dry_run: return None ap.name = req.args.new_name glob.PROJECT.update_modified() evt = sevts.p.ActionPointChanged(ap) evt.change_type = Event.Type.UPDATE_BASE asyncio.ensure_future(notif.broadcast_event(evt)) return None
def check_project_parameter(proj: CachedProject, parameter: ProjectParameter) -> None: hlp.is_valid_identifier(parameter.name) for pparam in proj.parameters: if parameter.id == pparam.id: continue if parameter.name == pparam.name: raise Arcor2Exception(f"Project parameter name {parameter.name} is duplicate.") check_parameter(parameter)
async def add_action_cb(req: rpc.project.AddActionRequest, ui: WsClient) -> None: assert glob.PROJECT assert glob.SCENE ap = glob.PROJECT.action_point(req.args.action_point_id) unique_name(req.args.name, glob.PROJECT.action_user_names()) if not hlp.is_valid_identifier(req.args.name): raise Arcor2Exception("Action name has to be valid Python identifier.") new_action = common.Action(common.uid(), req.args.name, req.args.type, req.args.parameters) updated_project = copy.deepcopy(glob.PROJECT) updated_ap = updated_project.action_point(req.args.action_point_id) updated_ap.actions.append(new_action) check_action_params(updated_project, new_action, find_object_action(new_action)) if req.dry_run: return None ap.actions.append(new_action) glob.PROJECT.update_modified() asyncio.ensure_future( notif.broadcast_event( events.ActionChanged(events.EventType.ADD, ap.id, data=new_action))) return None
async def rename_object_cb(req: rpc.scene.RenameObjectRequest, ui: WsClient) -> None: assert glob.SCENE target_obj = glob.SCENE.object(req.args.id) for obj_name in glob.SCENE.object_names(): if obj_name == req.args.new_name: raise Arcor2Exception("Object name already exists.") if not hlp.is_valid_identifier(req.args.new_name): raise Arcor2Exception("Object name invalid (should be snake_case).") if req.dry_run: return None target_obj.name = req.args.new_name glob.SCENE.update_modified() asyncio.ensure_future( notif.broadcast_event( events.SceneObjectChanged(events.EventType.UPDATE, data=target_obj))) return None
async def rename_action_point_cb(req: rpc.project.RenameActionPointRequest, ui: WsClient) -> None: assert glob.SCENE and glob.PROJECT ap = glob.PROJECT.action_point(req.args.action_point_id) if req.args.new_name == ap.name: return None if not hlp.is_valid_identifier(req.args.new_name): raise Arcor2Exception("Name has to be valid Python identifier.") unique_name(req.args.new_name, glob.PROJECT.action_points_names) if req.dry_run: return None ap.name = req.args.new_name glob.PROJECT.update_modified() asyncio.ensure_future( notif.broadcast_event( events.ActionPointChanged(events.EventType.UPDATE_BASE, data=ap.bare()))) return None
async def rename_action_point_joints_cb( req: srpc.p.RenameActionPointJoints.Request, ui: WsClient) -> None: assert glob.PROJECT ap, joints = glob.PROJECT.ap_and_joints(req.args.joints_id) hlp.is_valid_identifier(req.args.new_name) unique_name(req.args.new_name, glob.PROJECT.ap_joint_names(ap.id)) if req.dry_run: return None joints.name = req.args.new_name glob.PROJECT.update_modified() evt = sevts.p.JointsChanged(joints) evt.change_type = Event.Type.UPDATE_BASE asyncio.ensure_future(notif.broadcast_event(evt)) return None
async def add_action_point_cb(req: srpc.p.AddActionPoint.Request, ui: WsClient) -> None: assert glob.SCENE assert glob.PROJECT hlp.is_valid_identifier(req.args.name) unique_name(req.args.name, glob.PROJECT.action_points_names) check_ap_parent(req.args.parent) if req.dry_run: return None ap = glob.PROJECT.upsert_action_point(common.ActionPoint.uid(), req.args.name, req.args.position, req.args.parent) evt = sevts.p.ActionPointChanged(ap) evt.change_type = Event.Type.ADD asyncio.ensure_future(notif.broadcast_event(evt)) return None
async def rename_action_point_orientation_cb( req: srpc.p.RenameActionPointOrientation.Request, ui: WsClient) -> None: assert glob.PROJECT ap, ori = glob.PROJECT.bare_ap_and_orientation(req.args.orientation_id) hlp.is_valid_identifier(req.args.new_name) unique_name(req.args.new_name, glob.PROJECT.ap_orientation_names(ap.id)) if req.dry_run: return None ori.name = req.args.new_name glob.PROJECT.update_modified() evt = sevts.p.OrientationChanged(ori) evt.change_type = Event.Type.UPDATE_BASE asyncio.ensure_future(notif.broadcast_event(evt)) return None
def check_constant(constant: common.ProjectConstant) -> None: assert glob.PROJECT hlp.is_valid_identifier(constant.name) for const in glob.PROJECT.constants: if constant.id == const.id: continue if constant.name == const.name: raise Arcor2Exception("Name has to be unique.") # TODO check using (constant?) plugin import json val = json.loads(constant.value) if not isinstance(val, (int, float, str, bool)): raise Arcor2Exception("Only basic types are supported so far.")
def object_instance_from_res(object_name: str, object_id: str, cls_name: str) -> AnnAssign: try: is_valid_identifier(object_name) except Arcor2Exception as e: raise Arcor2Exception(f"Object name {object_name} invalid. {str(e)}") try: is_valid_type(cls_name) except Arcor2Exception as e: raise Arcor2Exception(f"Class name {cls_name} invalid. {str(e)}") return AnnAssign( target=Name(id=object_name, ctx=Store()), annotation=Name(id=cls_name, ctx=Load()), value=Subscript(value=get_name_attr("res", "objects"), slice=Index(value=Str(s=object_id, kind="")), ctx=Load()), simple=1, )
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)
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)
async def add_action_point_orientation_using_robot_cb( req: srpc.p.AddActionPointOrientationUsingRobot.Request, ui: WsClient) -> None: """Adds orientation and joints to the action point. :param req: :return: """ ensure_scene_started() assert glob.SCENE assert glob.PROJECT ap = glob.PROJECT.bare_action_point(req.args.action_point_id) hlp.is_valid_identifier(req.args.name) unique_name(req.args.name, glob.PROJECT.ap_orientation_names(ap.id)) if req.dry_run: return None new_pose = await get_end_effector_pose(req.args.robot.robot_id, req.args.robot.end_effector) if ap.parent: new_pose = tr.make_pose_rel_to_parent(glob.SCENE, glob.PROJECT, new_pose, ap.parent) orientation = common.NamedOrientation(req.args.name, new_pose.orientation) glob.PROJECT.upsert_orientation(ap.id, orientation) evt = sevts.p.OrientationChanged(orientation) evt.change_type = Event.Type.ADD evt.parent_id = ap.id asyncio.ensure_future(notif.broadcast_event(evt)) return None
async def add_action_point_cb(req: rpc.project.AddActionPointRequest, ui: WsClient) -> None: assert glob.SCENE assert glob.PROJECT unique_name(req.args.name, glob.PROJECT.action_points_names) check_ap_parent(req.args.parent) if not hlp.is_valid_identifier(req.args.name): raise Arcor2Exception("Name has to be valid Python identifier.") if req.dry_run: return None ap = common.ProjectActionPoint(common.uid(), req.args.name, req.args.position, req.args.parent) glob.PROJECT.action_points.append(ap) glob.PROJECT.update_modified() asyncio.ensure_future( notif.broadcast_event( events.ActionPointChanged(events.EventType.ADD, data=ap))) return None
async def add_object_to_scene(obj: SceneObject, add_to_scene=True, srv_obj_ok=False, dry_run: bool = False): """ :param obj: :param add_to_scene: Set to false to only create object instance and add its collision model (if any). :return: """ assert glob.SCENE if obj.type not in glob.OBJECT_TYPES: raise Arcor2Exception("Unknown object type.") obj_meta = glob.OBJECT_TYPES[obj.type] if obj_meta.disabled: raise Arcor2Exception("Object type disabled.") if srv_obj_ok: # just for internal usage if not obj_meta.needs_services <= osa.valid_service_types().keys(): raise Arcor2Exception( "Some of required services is not available.") if not obj_meta.needs_services <= glob.SERVICES_INSTANCES.keys(): raise Arcor2Exception( "Some of required services is not in the scene.") elif obj_meta.needs_services: raise Arcor2Exception("Service(s)-based object.") if obj_meta.abstract: raise Arcor2Exception("Cannot instantiate abstract type.") if obj.id in glob.SCENE_OBJECT_INSTANCES or obj.id in glob.SERVICES_INSTANCES: raise Arcor2Exception("Object/service with that id already exists.") if obj.name in instances_names(): raise Arcor2Exception("Name is already used.") if not hlp.is_valid_identifier(obj.name): raise Arcor2Exception("Object name invalid (should be snake_case).") if dry_run: return None await glob.logger.debug(f"Creating instance {obj.id} ({obj.type}).") if obj.type in otu.built_in_types_names(): cls = otu.get_built_in_type(obj.type) else: obj_type = await storage.get_object_type(obj.type) cls = hlp.type_def_from_source(obj_type.source, obj_type.id, Generic) coll_model: Optional[Models] = None if obj_meta.object_model: coll_model = obj_meta.object_model.model() if not obj_meta.needs_services: obj_inst = cls(obj.id, obj.name, obj.pose, coll_model) else: srv_args: List[Service] = [] for name, ttype in get_type_hints(cls.__init__).items(): # service arguments should be listed first if not issubclass(ttype, Service): break try: srv_args.append(glob.SERVICES_INSTANCES[ttype.__name__]) except KeyError: return False, f"Object type {obj.type} has invalid typ annotation in the constructor, " \ f"service {ttype.__name__} not available." try: obj_inst = cls(*srv_args, obj.id, obj.name, obj.pose, coll_model) # type: ignore except TypeError as e: raise Arcor2Exception("System error.") from e glob.SCENE_OBJECT_INSTANCES[obj.id] = obj_inst if add_to_scene: glob.SCENE.objects.append(obj) await collision(obj_inst, add=True) return None
async def auto_add_object_to_scene(obj_type_name: str, dry_run: bool = False) -> None: assert glob.SCENE if obj_type_name not in glob.OBJECT_TYPES: raise Arcor2Exception("Unknown object type.") if obj_type_name in otu.built_in_types_names(): raise Arcor2Exception("Does not work for built in types.") obj_meta = glob.OBJECT_TYPES[obj_type_name] if not obj_meta.needs_services: raise Arcor2Exception("Ordinary object.") if obj_meta.abstract: raise Arcor2Exception("Cannot instantiate abstract type.") if not obj_meta.needs_services <= osa.valid_service_types().keys(): raise Arcor2Exception("Some of required services is not available.") if not obj_meta.needs_services <= glob.SERVICES_INSTANCES.keys(): raise Arcor2Exception("Some of required services is not in the scene.") if dry_run: return None obj_type = await storage.get_object_type(obj_type_name) cls = hlp.type_def_from_source(obj_type.source, obj_type.id, Generic) args: List[Service] = [ glob.SERVICES_INSTANCES[srv_name] for srv_name in obj_meta.needs_services ] assert hasattr(cls, otu.SERVICES_METHOD_NAME) for obj_inst in cls.from_services(*args): # type: ignore assert isinstance(obj_inst, Generic) if not hlp.is_valid_identifier(obj_inst.name): # TODO add message to response await glob.logger.warning(f"Object id {obj_inst.id} invalid.") continue if obj_inst.id in glob.SCENE_OBJECT_INSTANCES: await glob.logger.warning( f"Object id {obj_inst.id} already in scene.") continue if obj_inst.name in instances_names(): await glob.logger.warning(f"Duplicate object name {obj_inst.name}." ) continue glob.SCENE_OBJECT_INSTANCES[obj_inst.id] = obj_inst obj = obj_inst.scene_object() glob.SCENE.objects.append(obj) asyncio.ensure_future( notif.broadcast_event( events.SceneObjectChanged(events.EventType.ADD, data=obj))) if obj_meta.object_model: obj_inst.collision_model = obj_meta.object_model.model() await collision(obj_inst, add=True) return None
def test_is_valid_identifier(val, expectation) -> None: with expectation: hlp.is_valid_identifier(val)
def test_is_valid_identifier(val): assert hlp.is_valid_identifier(val)