def test_export_import_figures(self, user_factory, project_factory): """ Test that ResultFigure instances are correctly restores after an export+import project """ # Prepare data user = user_factory() project = project_factory(user, "TestImportExportFigures") zip_path = os.path.join(os.path.dirname(tvb_data.__file__), 'connectivity', 'paupau.zip') TestFactory.import_zip_connectivity(user, project, zip_path) figure_service = FigureService() figure_service.store_result_figure(project, user, "png", IMG_DATA, "bla") figure_service.store_result_figure(project, user, "png", IMG_DATA, "bla") figures = list( figure_service.retrieve_result_figures(project, user)[0].values())[0] assert 2 == len(figures) # export, delete and the import project self.zip_path = ExportManager().export_project(project) assert self.zip_path is not None, "Exported file is none" self.project_service.remove_project(project.id) self.import_service.import_project_structure(self.zip_path, user.id) # Check that state is as before export: one operation, one DT, 2 figures retrieved_project = self.project_service.retrieve_projects_for_user( user.id)[0][0] count_operations = dao.get_filtered_operations(retrieved_project.id, None, is_count=True) assert 1 == count_operations count_datatypes = dao.count_datatypes(retrieved_project.id, DataType) assert 1 == count_datatypes figures = list( figure_service.retrieve_result_figures(retrieved_project, user)[0].values())[0] assert 2 == len(figures) assert "bla" in figures[0].name assert "bla" in figures[1].name image_path = utils.url2path(figures[0].file_path) img_data = Image.open(image_path).load() assert img_data is not None
class TestFigureService(TransactionalTestCase): """ Tests for the figure service """ def transactional_setup_method(self): self.figure_service = FigureService() self.user = TestFactory.create_user() self.project = TestFactory.create_project(admin=self.user) self.files_helper = FilesHelper() def transactional_teardown_method(self): self.delete_project_folders() def assertCanReadImage(self, image_path): try: Image.open(image_path).load() except (IOError, ValueError): raise AssertionError("Could not open %s as a image" % image_path) def store_test_png(self): self.figure_service.store_result_figure(self.project, self.user, "png", IMG_DATA, image_name="test-figure") def retrieve_images(self): figures_by_session, _ = self.figure_service.retrieve_result_figures(self.project, self.user) # flatten image session grouping figures = [] for fg in figures_by_session.itervalues(): figures.extend(fg) return figures def test_store_image(self): self.store_test_png() def test_store_image_from_operation(self): # test that image can be retrieved from operation test_operation = TestFactory.create_operation(test_user=self.user, test_project=self.project) self.figure_service.store_result_figure(self.project, self.user, "png", IMG_DATA, operation_id=test_operation.id) figures = dao.get_figures_for_operation(test_operation.id) assert 1 == len(figures) image_path = self.files_helper.get_images_folder(self.project.name) image_path = os.path.join(image_path, figures[0].file_path) self.assertCanReadImage(image_path) def test_store_and_retrieve_image(self): self.store_test_png() figures = self.retrieve_images() assert 1 == len(figures) image_path = utils.url2path(figures[0].file_path) self.assertCanReadImage(image_path) def test_load_figure(self): self.store_test_png() figures = self.retrieve_images() self.figure_service.load_figure(figures[0].id) def test_edit_figure(self): session_name = 'the altered ones' name = 'altered' self.store_test_png() figures = self.retrieve_images() self.figure_service.edit_result_figure(figures[0].id, session_name=session_name, name=name) figures_by_session, _ = self.figure_service.retrieve_result_figures(self.project, self.user) assert [session_name] == figures_by_session.keys() assert name == figures_by_session.values()[0][0].name def test_remove_figure(self): self.store_test_png() figures = self.retrieve_images() assert 1 == len(figures) self.figure_service.remove_result_figure(figures[0].id) figures = self.retrieve_images() assert 0 == len(figures)
class FigureServiceTest(TransactionalTestCase): """ Tests for the figure service """ def setUp(self): self.figure_service = FigureService() self.user = TestFactory.create_user() self.project = TestFactory.create_project(admin=self.user) self.files_helper = FilesHelper() def tearDown(self): self.delete_project_folders() def assertCanReadImage(self, image_path): try: Image.open(image_path).load() except (IOError, ValueError): self.fail("Could not open %s as a image" % image_path) def store_test_png(self): self.figure_service.store_result_figure(self.project, self.user, "png", IMG_DATA, image_name="test-figure") def retrieve_images(self): figures_by_session, _ = self.figure_service.retrieve_result_figures( self.project, self.user) # flatten image session grouping figures = [] for fg in figures_by_session.itervalues(): figures.extend(fg) return figures def test_store_image(self): self.store_test_png() def test_store_image_from_operation(self): # test that image can be retrieved from operation test_operation = TestFactory.create_operation( test_user=self.user, test_project=self.project) self.figure_service.store_result_figure(self.project, self.user, "png", IMG_DATA, operation_id=test_operation.id) figures = dao.get_figures_for_operation(test_operation.id) self.assertEqual(1, len(figures)) image_path = self.files_helper.get_images_folder(self.project.name) image_path = os.path.join(image_path, figures[0].file_path) self.assertCanReadImage(image_path) def test_store_and_retrieve_image(self): self.store_test_png() figures = self.retrieve_images() self.assertEqual(1, len(figures)) image_path = utils.url2path(figures[0].file_path) self.assertCanReadImage(image_path) def test_load_figure(self): self.store_test_png() figures = self.retrieve_images() self.figure_service.load_figure(figures[0].id) def test_edit_figure(self): session_name = 'the altered ones' name = 'altered' self.store_test_png() figures = self.retrieve_images() self.figure_service.edit_result_figure(figures[0].id, session_name=session_name, name=name) figures_by_session, _ = self.figure_service.retrieve_result_figures( self.project, self.user) self.assertEqual([session_name], figures_by_session.keys()) self.assertEqual(name, figures_by_session.values()[0][0].name) def test_remove_figure(self): self.store_test_png() figures = self.retrieve_images() self.assertEqual(1, len(figures)) self.figure_service.remove_result_figure(figures[0].id) figures = self.retrieve_images() self.assertEqual(0, len(figures))
class FigureController(ProjectController): """ Resulting Figures are user-saved figures with specific visualizers or TVB pages which are considered important. """ def __init__(self): ProjectController.__init__(self) self.storage_interface = StorageInterface() self.figure_service = FigureService() @cherrypy.expose @handle_error(redirect=False) @check_user @context_selected def storeresultfigure(self, img_type, **kwargs): """Create preview for current displayed canvas and store image in current session, for future comparison.""" project = common.get_current_project() user = common.get_logged_user() suggested_name = kwargs.get("suggestedName") self.figure_service.store_result_figure(project, user, img_type, kwargs['export_data'], suggested_name) @expose_page @context_selected def displayresultfigures(self, selected_session='all_sessions'): """ Collect and display saved previews, grouped by session.""" project = common.get_current_project() user = common.get_logged_user() data, all_sessions_info = self.figure_service.retrieve_result_figures( project, user, selected_session) manage_figure_title = "Figures for " + str( selected_session) + " category" if selected_session == 'all_sessions': manage_figure_title = "Figures for all categories" template_specification = dict(mainContent="project/figures_display", title="Stored Visualizer Previews", controlPage=None, displayControl=False, selected_sessions_data=data, all_sessions_info=all_sessions_info, selected_session=selected_session, manageFigureTitle=manage_figure_title) template_specification = self.fill_default_attributes( template_specification, subsection='figures') return template_specification @cherrypy.expose @handle_error(redirect=True) @check_user @context_selected def editresultfigures(self, remove_figure=False, rename_session=False, remove_session=False, **data): """ This method knows how to handle the following actions: remove figure, update figure, remove session and update session. """ project = common.get_current_project() user = common.get_logged_user() redirect_url = '/project/figure/displayresultfigures' if "selected_session" in data and data[ "selected_session"] is not None and len( data["selected_session"]): redirect_url += '/' + data["selected_session"] del data["selected_session"] figure_id = None if "figure_id" in data: figure_id = data["figure_id"] del data["figure_id"] if cherrypy.request.method == 'POST' and rename_session: successfully_updated = True if "old_session_name" in data and "new_session_name" in data: figures_dict, _ = self.figure_service.retrieve_result_figures( project, user, data["old_session_name"]) for _key, value in figures_dict.items(): for figure in value: new_data = { "name": figure.name, "session_name": data["new_session_name"] } success = self._update_figure(figure.id, **new_data) if not success: successfully_updated = False if successfully_updated: common.set_info_message( "The session was successfully updated!") else: common.set_error_message( "The session was not successfully updated! " "There could be some figures that still refer to the old session." ) elif cherrypy.request.method == 'POST' and remove_session: successfully_removed = True if "old_session_name" in data: figures_dict, _ = self.figure_service.retrieve_result_figures( project, user, data["old_session_name"]) for _key, value in figures_dict.items(): for figure in value: success = self.figure_service.remove_result_figure( figure.id) if not success: successfully_removed = False if successfully_removed: common.set_info_message( "The session was removed successfully!") else: common.set_error_message( "The session was not entirely removed!") elif cherrypy.request.method == 'POST' and remove_figure and figure_id is not None: success = self.figure_service.remove_result_figure(figure_id) if success: common.set_info_message("Figure removed successfully!") else: common.set_error_message("Figure could not be removed!") elif figure_id is not None: self._update_figure(figure_id, **data) raise cherrypy.HTTPRedirect(redirect_url) def _update_figure(self, figure_id, **data): """ Updates the figure details to the given data. """ try: data = EditPreview().to_python(data) self.figure_service.edit_result_figure(figure_id, **data) common.set_info_message('Figure details updated successfully.') return True except formencode.Invalid as excep: self.logger.debug(excep) common.set_error_message(excep.message) return False @cherrypy.expose @handle_error(redirect=False) @check_user def downloadimage(self, figure_id): """ Allow a user to download a figure. """ figure = self.figure_service.load_figure(figure_id) image_folder = self.storage_interface.get_images_folder( figure.project.name) figure_path = os.path.join(image_folder, figure.file_path) return serve_file(figure_path, "image/" + figure.file_format, "attachment", "%s.%s" % (figure.name, figure.file_format)) @cherrypy.expose @handle_error(redirect=False) @using_template("overlay") @check_user def displayzoomedimage(self, figure_id): """ Displays the image with the specified id in an overlay dialog. """ figure = self.figure_service.load_figure(figure_id) figures_folder = self.storage_interface.get_images_folder( figure.project.name) figure_full_path = os.path.join(figures_folder, figure.file_path) figure_file_path = utils.path2url_part(figure_full_path) description = figure.session_name + " - " + figure.name template_dictionary = dict(figure_file_path=figure_file_path) return self.fill_overlay_attributes(template_dictionary, "Detail", description, "project/figure_zoom_overlay", "lightbox")
class TestFigureService(TransactionalTestCase): """ Tests for the figure service """ def transactional_setup_method(self): self.figure_service = FigureService() self.user = TestFactory.create_user() self.project = TestFactory.create_project(admin=self.user) self.files_helper = FilesHelper() def transactional_teardown_method(self): self.delete_project_folders() def assertCanReadImage(self, image_path): try: Image.open(image_path).load() except (IOError, ValueError): raise AssertionError("Could not open %s as a image" % image_path) def store_test_png(self): self.figure_service.store_result_figure(self.project, self.user, "png", IMG_DATA, "test-figure") def retrieve_images(self): figures_by_session, _ = self.figure_service.retrieve_result_figures( self.project, self.user) # flatten image session grouping figures = [] for fg in figures_by_session.values(): figures.extend(fg) return figures def test_store_image(self): self.store_test_png() def test_store_and_retrieve_image(self): self.store_test_png() figures = self.retrieve_images() assert 1 == len(figures) image_path = utils.url2path(figures[0].file_path) self.assertCanReadImage(image_path) def test_load_figure(self): self.store_test_png() figures = self.retrieve_images() self.figure_service.load_figure(figures[0].id) def test_edit_figure(self): session_name = 'the altered ones' name = 'altered' self.store_test_png() figures = self.retrieve_images() self.figure_service.edit_result_figure(figures[0].id, session_name=session_name, name=name) figures_by_session, _ = self.figure_service.retrieve_result_figures( self.project, self.user) assert [session_name] == list(figures_by_session) assert name == list(figures_by_session.values())[0][0].name def test_remove_figure(self): self.store_test_png() figures = self.retrieve_images() assert 1 == len(figures) self.figure_service.remove_result_figure(figures[0].id) figures = self.retrieve_images() assert 0 == len(figures)
class FigureController(ProjectController): """ Resulting Figures are user-saved figures with specific visualizers or TVB pages which are considered important. """ def __init__(self): ProjectController.__init__(self) self.files_helper = FilesHelper() self.figure_service = FigureService() @cherrypy.expose @handle_error(redirect=False) @check_user @context_selected def storeresultfigure(self, img_type, **kwargs): """Create preview for current displayed canvas and store image in current session, for future comparison.""" project = common.get_current_project() user = common.get_logged_user() operation_id = kwargs.get("operationId") suggested_name = kwargs.get("suggestedName") self.figure_service.store_result_figure(project, user, img_type, kwargs['export_data'], image_name=suggested_name, operation_id=operation_id) @expose_page @context_selected def displayresultfigures(self, selected_session='all_sessions'): """ Collect and display saved previews, grouped by session.""" project = common.get_current_project() user = common.get_logged_user() data, all_sessions_info = self.figure_service.retrieve_result_figures(project, user, selected_session) manage_figure_title = "Figures for " + str(selected_session) + " category" if selected_session == 'all_sessions': manage_figure_title = "Figures for all categories" template_specification = dict(mainContent="project/figures_display", title="Stored Visualizer Previews", controlPage=None, displayControl=False, selected_sessions_data=data, all_sessions_info=all_sessions_info, selected_session=selected_session, manageFigureTitle=manage_figure_title) template_specification = self.fill_default_attributes(template_specification, subsection='figures') return template_specification @cherrypy.expose @handle_error(redirect=True) @check_user @context_selected def editresultfigures(self, remove_figure=False, rename_session=False, remove_session=False, **data): """ This method knows how to handle the following actions: remove figure, update figure, remove session and update session. """ project = common.get_current_project() user = common.get_logged_user() redirect_url = '/project/figure/displayresultfigures' if "selected_session" in data and data["selected_session"] is not None and len(data["selected_session"]): redirect_url += '/' + data["selected_session"] del data["selected_session"] figure_id = None if "figure_id" in data: figure_id = data["figure_id"] del data["figure_id"] if cherrypy.request.method == 'POST' and rename_session: successfully_updated = True if "old_session_name" in data and "new_session_name" in data: figures_dict, _ = self.figure_service.retrieve_result_figures(project, user, data["old_session_name"]) for _key, value in figures_dict.iteritems(): for figure in value: new_data = {"name": figure.name, "session_name": data["new_session_name"]} success = self._update_figure(figure.id, **new_data) if not success: successfully_updated = False if successfully_updated: common.set_info_message("The session was successfully updated!") else: common.set_error_message("The session was not successfully updated! " "There could be some figures that still refer to the old session.") elif cherrypy.request.method == 'POST' and remove_session: successfully_removed = True if "old_session_name" in data: figures_dict, _ = self.figure_service.retrieve_result_figures(project, user, data["old_session_name"]) for _key, value in figures_dict.iteritems(): for figure in value: success = self.figure_service.remove_result_figure(figure.id) if not success: successfully_removed = False if successfully_removed: common.set_info_message("The session was removed successfully!") else: common.set_error_message("The session was not entirely removed!") elif cherrypy.request.method == 'POST' and remove_figure and figure_id is not None: success = self.figure_service.remove_result_figure(figure_id) if success: common.set_info_message("Figure removed successfully!") else: common.set_error_message("Figure could not be removed!") elif figure_id is not None: self._update_figure(figure_id, **data) raise cherrypy.HTTPRedirect(redirect_url) def _update_figure(self, figure_id, **data): """ Updates the figure details to the given data. """ try: data = EditPreview().to_python(data) self.figure_service.edit_result_figure(figure_id, **data) common.set_info_message('Figure details updated successfully.') return True except formencode.Invalid, excep: self.logger.debug(excep) common.set_error_message(excep.message) return False