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))
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
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))
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")
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
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])