From cedde58569b56456ef508917b77e7a151e375aa9 Mon Sep 17 00:00:00 2001 From: Cezary Czernecki <ccezary@ethz.ch> Date: Wed, 4 Sep 2019 14:42:25 +0200 Subject: [PATCH] SSDM-8701 excel parser csv support --- .../v1/impl/MasterDataRegistrationHelper.java | 67 ++++--- .../as/services/xls-import-api/entrypoint.py | 18 +- .../xls-import-api/parsers/__init__.py | 5 +- .../xls-import-api/parsers/parsers_facade.py | 18 +- .../parsers/poi_to_definition/__init__.py | 2 - .../parsers/to_definition/__init__.py | 3 + .../csv_to_definition/__init__.py | 0 .../csv_to_definition/csv_to_definition.py | 28 +++ .../definition.py | 0 .../poi_to_definition/__init__.py | 0 .../poi_to_definition/definition_parsers.py | 49 ++--- .../poi_to_definition/poi_cleaner.py | 8 +- .../poi_to_definition/poi_to_definition.py | 0 .../xls-import-api/utils/file_handling.py | 3 + .../excelimport/AbstractImportTest.java | 9 +- .../plugin/excelimport/ImportFromCsvTest.java | 59 ++++++ .../ImportVocabularyTypesTest.java | 1 - .../plugin/excelimport/TestUtils.java | 171 +++++++----------- .../excelimport/test_files/csv/types.csv | 7 + 19 files changed, 262 insertions(+), 186 deletions(-) delete mode 100644 openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/__init__.py create mode 100644 openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/__init__.py create mode 100644 openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/csv_to_definition/__init__.py create mode 100644 openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/csv_to_definition/csv_to_definition.py rename openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/{poi_to_definition => to_definition}/definition.py (100%) create mode 100644 openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/poi_to_definition/__init__.py rename openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/{ => to_definition}/poi_to_definition/definition_parsers.py (64%) rename openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/{ => to_definition}/poi_to_definition/poi_cleaner.py (90%) rename openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/{ => to_definition}/poi_to_definition/poi_to_definition.py (100%) create mode 100644 openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportFromCsvTest.java create mode 100644 openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/csv/types.csv diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/jython/api/v1/impl/MasterDataRegistrationHelper.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/jython/api/v1/impl/MasterDataRegistrationHelper.java index 8d5e02c3dee..dcddcc9c160 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/jython/api/v1/impl/MasterDataRegistrationHelper.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/jython/api/v1/impl/MasterDataRegistrationHelper.java @@ -17,6 +17,8 @@ package ch.systemsx.cisd.openbis.generic.server.jython.api.v1.impl; import java.io.File; +import java.io.IOException; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -31,31 +33,24 @@ import ch.systemsx.cisd.common.logging.LogFactory; /** * Helper class to be used in initialize-master-data.py. - * + * * @author Franz-Josef Elmer */ -public class MasterDataRegistrationHelper -{ +public class MasterDataRegistrationHelper { private static Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, MasterDataRegistrationHelper.class); - + private File masterDataFolder; - public MasterDataRegistrationHelper(Collection<?> systemPaths) - { - for (Object systemPath : systemPaths) - { - if (systemPath != null) - { + public MasterDataRegistrationHelper(Collection<?> systemPaths) { + for (Object systemPath : systemPaths) { + if (systemPath != null) { String systemPathString = String.valueOf(systemPath); - if (systemPathString.contains("core-plugins")) - { + if (systemPathString.contains("core-plugins")) { masterDataFolder = new File(new File(systemPathString), "master-data"); - if (masterDataFolder.exists() == false) - { + if (masterDataFolder.exists()) { throw new IllegalArgumentException("Folder does not exist: " + masterDataFolder.getAbsolutePath()); } - if (masterDataFolder.isFile()) - { + if (masterDataFolder.isFile()) { throw new IllegalArgumentException("Is not a folder but a file: " + masterDataFolder.getAbsolutePath()); } operationLog.info("Master data folder: " + masterDataFolder.getAbsolutePath()); @@ -66,14 +61,11 @@ public class MasterDataRegistrationHelper throw new IllegalArgumentException("Does not contain path to the core plugin: " + systemPaths); } - public List<byte[]> listXlsByteArrays() - { + public List<byte[]> listXlsByteArrays() { List<byte[]> result = new ArrayList<>(); - for (File file : masterDataFolder.listFiles()) - { + for (File file : masterDataFolder.listFiles()) { String name = file.getName(); - if (name.endsWith(".xls") || name.endsWith(".xlsx")) - { + if (name.endsWith(".xls") || name.endsWith(".xlsx")) { operationLog.info("load master data " + file.getName()); result.add(FileUtilities.loadToByteArray(file)); } @@ -81,34 +73,39 @@ public class MasterDataRegistrationHelper return result; } - public Map<String, String> getAllScripts() - { + public List<byte[]> listCsvByteArrays() throws IOException { + List<byte[]> result = new ArrayList<>(); + for (File file : masterDataFolder.listFiles()) { + String name = file.getName(); + if (name.endsWith(".csv")) { + operationLog.info("load master data " + file.getName()); + result.add(Files.readAllBytes(file.toPath())); + } + } + return result; + } + + public Map<String, String> getAllScripts() { Map<String, String> result = new TreeMap<>(); File scriptsFolder = new File(masterDataFolder, "scripts"); - if (scriptsFolder.isDirectory()) - { + if (scriptsFolder.isDirectory()) { gatherScripts(result, scriptsFolder, scriptsFolder); } return result; } - private void gatherScripts(Map<String, String> scripts, File rootFolder, File file) - { - if (file.isFile()) - { + private void gatherScripts(Map<String, String> scripts, File rootFolder, File file) { + if (file.isFile()) { String scriptPath = FileUtilities.getRelativeFilePath(rootFolder, file); scripts.put(scriptPath, FileUtilities.loadToString(file)); operationLog.info("Script " + scriptPath + " loaded"); } - if (file.isDirectory()) - { + if (file.isDirectory()) { File[] files = file.listFiles(); - for (File child : files) - { + for (File child : files) { gatherScripts(scripts, rootFolder, child); } } } - } diff --git a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/entrypoint.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/entrypoint.py index 9806b27718b..ff5e9b18ff8 100644 --- a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/entrypoint.py +++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/entrypoint.py @@ -3,7 +3,7 @@ import os from ch.ethz.sis.openbis.generic.asapi.v3.dto.operation import SynchronousOperationExecutionOptions from ch.systemsx.cisd.common.exceptions import UserFailureException from ch.systemsx.cisd.openbis.generic.server import CommonServiceProvider -from parsers import get_creations_from, get_definitions_from, get_creation_metadata_from, \ +from parsers import get_creations_from, get_definitions_from_xls, get_definitions_from_csv, get_creation_metadata_from, \ CreationOrUpdateToOperationParser, versionable_types from processors import OpenbisDuplicatesHandler, PropertiesLabelHandler, DuplicatesHandler, \ unify_properties_representation_of @@ -14,9 +14,9 @@ from utils.openbis_utils import get_version_name_for, get_metadata_name_for REMOVE_VERSIONS = False -def validate_data(xls_byte_arrays, update_mode, xls_name): - if xls_byte_arrays is None: - raise UserFailureException('Excel sheet has not been provided. "xls" parameter is None') +def validate_data(xls_byte_arrays, csv_strings, update_mode, xls_name): + if xls_byte_arrays is None and csv_strings is None: + raise UserFailureException('Nor Excel sheet nor csv has not been provided. "xls" and "csv" parameters are None') if update_mode not in ['IGNORE_EXISTING', 'FAIL_IF_EXISTS', 'UPDATE_IF_EXISTS']: raise UserFailureException( 'Update mode has to be one of following: IGNORE_EXISTING FAIL_IF_EXISTS UPDATE_IF_EXISTS but was ' + ( @@ -69,11 +69,17 @@ def process(context, parameters): search_engine = SearchEngine(api, session_token) xls_byte_arrays = parameters.get('xls', None) + csv_strings = parameters.get('csv', None) xls_name = parameters.get('xls_name', None) scripts = parameters.get('scripts', {}) update_mode = parameters.get('update_mode', None) - validate_data(xls_byte_arrays, update_mode, xls_name) - definitions = get_definitions_from(xls_byte_arrays) + validate_data(xls_byte_arrays, csv_strings, update_mode, xls_name) + definitions = get_definitions_from_xls(xls_byte_arrays) + print(xls_byte_arrays) + print(csv_strings) + print ("EOEOOEOE") + print(definitions) + definitions.extend(get_definitions_from_csv(csv_strings)) creations = get_creations_from(definitions, FileHandler(scripts)) creations_metadata = get_creation_metadata_from(definitions) creations = DuplicatesHandler.get_distinct_creations(creations) diff --git a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/__init__.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/__init__.py index 28a31b2287a..4bd91747064 100644 --- a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/__init__.py +++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/__init__.py @@ -7,8 +7,9 @@ from .definition_to_creation import PropertyTypeDefinitionToCreationType, Vocabu SampleDefinitionToCreationType, ScriptDefinitionToCreationType from .definition_to_creation_metadata import DefinitionToCreationMetadataParser from .excel_to_poi import ExcelToPoiParser -from .parsers_facade import get_creations_from, get_definitions_from, get_creation_metadata_from -from .poi_to_definition import PoiToDefinitionParser, Definition +from .parsers_facade import get_creations_from, get_definitions_from_xls, get_definitions_from_csv, \ + get_creation_metadata_from +from .to_definition import PoiToDefinitionParser, CsvReaderToDefinitionParser, Definition from .creation_to_update import CreationToUpdateParser, UpdateTypes, PropertyTypeCreationToUpdateType, \ VocabularyCreationToUpdateType, VocabularyTermCreationToUpdateType, PropertyAssignmentCreationToUpdateType, \ SampleTypeCreationToUpdateType, ExperimentTypeCreationToUpdateType, DatasetTypeCreationToUpdateType, \ diff --git a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/parsers_facade.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/parsers_facade.py index 51624c520c9..a2884641bee 100644 --- a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/parsers_facade.py +++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/parsers_facade.py @@ -1,21 +1,29 @@ from .definition_to_creation import DefinitionToCreationParser from .excel_to_poi import ExcelToPoiParser -from .poi_to_definition import PoiToDefinitionParser - +from .to_definition import PoiToDefinitionParser, CsvReaderToDefinitionParser from .definition_to_creation_metadata import DefinitionToCreationMetadataParser -def get_definitions_from(xls_byte_arrays): +def get_definitions_from_xls(xls_byte_arrays): definitions = [] - for excel_byte_array in xls_byte_arrays: + for excel_byte_array in xls_byte_arrays or []: poi_definitions = ExcelToPoiParser.parse(excel_byte_array) partial_definitions = PoiToDefinitionParser.parse(poi_definitions) definitions.extend(partial_definitions) return definitions +def get_definitions_from_csv(csv_strings): + definitions = [] + for csv_string in csv_strings or []: + csv_definitions = CsvReaderToDefinitionParser.parse(csv_string) + partial_definitions = PoiToDefinitionParser.parse(csv_definitions) + definitions.extend(partial_definitions) + + return definitions + + def get_creations_from(definitions, context): - pass return DefinitionToCreationParser.parse(definitions, context) diff --git a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/__init__.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/__init__.py deleted file mode 100644 index 3d310af376a..00000000000 --- a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .poi_to_definition import PoiToDefinitionParser -from .definition import Definition diff --git a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/__init__.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/__init__.py new file mode 100644 index 00000000000..0c359051546 --- /dev/null +++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/__init__.py @@ -0,0 +1,3 @@ +from .poi_to_definition.poi_to_definition import PoiToDefinitionParser +from .csv_to_definition.csv_to_definition import CsvReaderToDefinitionParser +from .definition import Definition diff --git a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/csv_to_definition/__init__.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/csv_to_definition/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/csv_to_definition/csv_to_definition.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/csv_to_definition/csv_to_definition.py new file mode 100644 index 00000000000..bb3fcffad07 --- /dev/null +++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/csv_to_definition/csv_to_definition.py @@ -0,0 +1,28 @@ +from StringIO import StringIO +import csv + + +class CsvReaderToDefinitionParser(): + + @staticmethod + def parse(csv_string): + def is_row_empty(row): + return not ''.join(row).strip() + + f = StringIO("".join(map(chr, csv_string))) + reader = csv.reader(f, delimiter=',') + definitions = [] + definition_rows = [] + previous_row_empty = False + for row in reader: + if is_row_empty(row) and previous_row_empty: + break + if is_row_empty(row): + definitions.append(definition_rows) + definition_rows = [] + previous_row_empty = True + continue + previous_row_empty = False + definition_rows.append({k: v for k, v in enumerate(row) if v != ''}) + + return definitions diff --git a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/definition.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/definition.py similarity index 100% rename from openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/definition.py rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/definition.py diff --git a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/poi_to_definition/__init__.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/poi_to_definition/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/definition_parsers.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/poi_to_definition/definition_parsers.py similarity index 64% rename from openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/definition_parsers.py rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/poi_to_definition/definition_parsers.py index d17255c0f85..c5ccd24ee88 100644 --- a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/definition_parsers.py +++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/poi_to_definition/definition_parsers.py @@ -1,18 +1,20 @@ from java.lang import UnsupportedOperationException -from .definition import Definition +from ..definition import Definition from .poi_cleaner import PoiCleaner class DefinitionParserFactory(object): - @staticmethod - def get_parser(definition_type): - if definition_type in ['VOCABULARY_TYPE', 'SAMPLE_TYPE', 'EXPERIMENT_TYPE', 'DATASET_TYPE', 'EXPERIMENT', 'SAMPLE']: - return GeneralDefinitionParser - elif definition_type in ['PROPERTY_TYPE', 'SPACE', 'PROJECT']: - return PropertiesOnlyDefinitionParser - else: - raise UnsupportedOperationException("Definition of " + str(definition_type) + " is not supported (probably yet).") + @staticmethod + def get_parser(definition_type): + if definition_type in ['VOCABULARY_TYPE', 'SAMPLE_TYPE', 'EXPERIMENT_TYPE', 'DATASET_TYPE', 'EXPERIMENT', + 'SAMPLE']: + return GeneralDefinitionParser + elif definition_type in ['PROPERTY_TYPE', 'SPACE', 'PROJECT']: + return PropertiesOnlyDefinitionParser + else: + raise UnsupportedOperationException( + "Definition of " + str(definition_type) + " is not supported (probably yet).") class PropertiesOnlyDefinitionParser(object): @@ -25,15 +27,20 @@ class PropertiesOnlyDefinitionParser(object): PROPERTIES_VALUES_ROW_START = 2 row_numbers = { - 'DEFINITION_TYPE_ROW' : DEFINITION_TYPE_ROW, - 'DEFINITION_TYPE_CELL' : DEFINITION_TYPE_CELL, - 'ATTRIBUTES_HEADER_ROW' : None, - 'ATTRIBUTES_VALUES_ROW' : None, - 'PROPERTIES_HEADER_ROW' : PROPERTIES_HEADER_ROW, - 'PROPERTIES_VALUES_ROW_START' : PROPERTIES_VALUES_ROW_START + 'DEFINITION_TYPE_ROW': DEFINITION_TYPE_ROW, + 'DEFINITION_TYPE_CELL': DEFINITION_TYPE_CELL, + 'ATTRIBUTES_HEADER_ROW': None, + 'ATTRIBUTES_VALUES_ROW': None, + 'PROPERTIES_HEADER_ROW': PROPERTIES_HEADER_ROW, + 'PROPERTIES_VALUES_ROW_START': PROPERTIES_VALUES_ROW_START } + print("PREPREPRPPRE") + print(poi_definition) poi_definition = PoiCleaner.clean_data(poi_definition, row_numbers) + print("POSOPOPSPOPSPOSPOOPS") + print(poi_definition) + definition = Definition() definition.type = poi_definition[DEFINITION_TYPE_ROW][DEFINITION_TYPE_CELL] if PropertiesOnlyDefinitionParser.hasProperties(poi_definition): @@ -65,12 +72,12 @@ class GeneralDefinitionParser(object): PROPERTIES_VALUES_ROW_START = 4 row_numbers = { - 'DEFINITION_TYPE_ROW' : DEFINITION_TYPE_ROW, - 'DEFINITION_TYPE_CELL' : DEFINITION_TYPE_CELL, - 'ATTRIBUTES_HEADER_ROW' : ATTRIBUTES_HEADER_ROW, - 'ATTRIBUTES_VALUES_ROW' : ATTRIBUTES_VALUES_ROW, - 'PROPERTIES_HEADER_ROW' : PROPERTIES_HEADER_ROW, - 'PROPERTIES_VALUES_ROW_START' : PROPERTIES_VALUES_ROW_START + 'DEFINITION_TYPE_ROW': DEFINITION_TYPE_ROW, + 'DEFINITION_TYPE_CELL': DEFINITION_TYPE_CELL, + 'ATTRIBUTES_HEADER_ROW': ATTRIBUTES_HEADER_ROW, + 'ATTRIBUTES_VALUES_ROW': ATTRIBUTES_VALUES_ROW, + 'PROPERTIES_HEADER_ROW': PROPERTIES_HEADER_ROW, + 'PROPERTIES_VALUES_ROW_START': PROPERTIES_VALUES_ROW_START } poi_definition = PoiCleaner.clean_data(poi_definition, row_numbers) diff --git a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/poi_cleaner.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/poi_to_definition/poi_cleaner.py similarity index 90% rename from openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/poi_cleaner.py rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/poi_to_definition/poi_cleaner.py index df03358a840..e4698a6c51d 100644 --- a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/poi_cleaner.py +++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/poi_to_definition/poi_cleaner.py @@ -25,13 +25,14 @@ class PoiCleaner(object): If there's no corresponding value, None is inserted. 4. Headers to lowercase ''' - definition[DEFINITION_TYPE_ROW] = {0:definition[DEFINITION_TYPE_ROW][DEFINITION_TYPE_CELL]} + definition[DEFINITION_TYPE_ROW] = {0: definition[DEFINITION_TYPE_ROW][DEFINITION_TYPE_CELL]} if ATTRIBUTES_HEADER_ROW is not None: PoiCleaner.delete_empty_cells_from(definition, ATTRIBUTES_HEADER_ROW) if ATTRIBUTES_VALUES_ROW is not None: PoiCleaner.delete_cells_if_no_header(definition, ATTRIBUTES_HEADER_ROW, ATTRIBUTES_VALUES_ROW) - PoiCleaner.create_cells_if_no_value_but_header_exists(definition, ATTRIBUTES_HEADER_ROW, ATTRIBUTES_VALUES_ROW) + PoiCleaner.create_cells_if_no_value_but_header_exists(definition, ATTRIBUTES_HEADER_ROW, + ATTRIBUTES_VALUES_ROW) definition[ATTRIBUTES_HEADER_ROW] = PoiCleaner.dict_values_to_lowercase(definition[ATTRIBUTES_HEADER_ROW]) if PROPERTIES_HEADER_ROW is not None and PoiCleaner.hasProperties(definition, PROPERTIES_HEADER_ROW): @@ -39,7 +40,8 @@ class PoiCleaner(object): if PROPERTIES_VALUES_ROW_START is not None: for property_value_row_num in range(PROPERTIES_VALUES_ROW_START, len(definition)): PoiCleaner.delete_cells_if_no_header(definition, PROPERTIES_HEADER_ROW, property_value_row_num) - PoiCleaner.create_cells_if_no_value_but_header_exists(definition, PROPERTIES_HEADER_ROW, property_value_row_num) + PoiCleaner.create_cells_if_no_value_but_header_exists(definition, PROPERTIES_HEADER_ROW, + property_value_row_num) definition[PROPERTIES_HEADER_ROW] = PoiCleaner.dict_values_to_lowercase(definition[PROPERTIES_HEADER_ROW]) return definition diff --git a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/poi_to_definition.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/poi_to_definition/poi_to_definition.py similarity index 100% rename from openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/poi_to_definition.py rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/to_definition/poi_to_definition/poi_to_definition.py diff --git a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/utils/file_handling.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/utils/file_handling.py index ec48f01ed85..b053b8ccc91 100644 --- a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/utils/file_handling.py +++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/utils/file_handling.py @@ -4,4 +4,7 @@ class FileHandler(object): self.scripts = scripts def get_script(self, script_path): + print("SSSSSSS") + print(script_path) + print(self.scripts) return self.scripts[script_path] diff --git a/openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/AbstractImportTest.java b/openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/AbstractImportTest.java index 19f8b06059e..19e01483f8d 100644 --- a/openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/AbstractImportTest.java +++ b/openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/AbstractImportTest.java @@ -10,16 +10,14 @@ import ch.systemsx.cisd.openbis.generic.server.util.TestInitializer; import ch.systemsx.cisd.openbis.generic.shared.Constants; import ch.systemsx.cisd.openbis.generic.shared.coreplugin.CorePluginsUtils; -public class AbstractImportTest extends AbstractTransactionalTestNGSpringContextTests -{ +public class AbstractImportTest extends AbstractTransactionalTestNGSpringContextTests { protected String FILES_DIR; private String XLS_VERSIONING_DIR = "xls-import.version-data-file"; @BeforeSuite - public void setupSuite() - { + public void setupSuite() { System.setProperty(XLS_VERSIONING_DIR, "./versioning.bin"); System.setProperty(CorePluginsUtils.CORE_PLUGINS_FOLDER_KEY, "dist/core-plugins"); System.setProperty(Constants.ENABLED_MODULES_KEY, "xls-import"); @@ -27,8 +25,7 @@ public class AbstractImportTest extends AbstractTransactionalTestNGSpringContext } @AfterMethod - public void afterTest() - { + public void afterTest() { File f = new File("./versioning.bin"); f.delete(); } diff --git a/openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportFromCsvTest.java b/openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportFromCsvTest.java new file mode 100644 index 00000000000..0bebe62075d --- /dev/null +++ b/openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportFromCsvTest.java @@ -0,0 +1,59 @@ +package ch.ethz.sis.openbis.systemtest.plugin.excelimport; + +import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.Vocabulary; +import ch.ethz.sis.openbis.generic.server.asapi.v3.IApplicationServerInternalApi; +import org.apache.commons.io.FilenameUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.Rollback; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.transaction.annotation.Transactional; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.nio.file.Paths; + +import static org.testng.Assert.assertNotNull; + +@ContextConfiguration(locations = "classpath:applicationContext.xml") +@Transactional(transactionManager = "transaction-manager") +@Rollback +public class ImportFromCsvTest extends AbstractImportTest { + + @Autowired + private IApplicationServerInternalApi v3api; + + private static final String TEST_USER = "test"; + + private static final String PASSWORD = "password"; + + private static final String FULL_TYPES_CSV = "csv/types.csv"; + + private String sessionToken; + + @BeforeClass + public void setupClass() throws IOException { + String f = ImportExperimentTypesTest.class.getName().replace(".", "/"); + FILES_DIR = f.substring(0, f.length() - ImportExperimentTypesTest.class.getSimpleName().length()) + "/test_files/"; + } + + @BeforeMethod + public void beforeTest() { + sessionToken = v3api.login(TEST_USER, PASSWORD); + } + + @Test + @DirtiesContext + public void testNormalExperimentTypesAreCreated() throws Exception { + // GIVEN + TestUtils.createFromCsv(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, FULL_TYPES_CSV))); + // WHEN + Vocabulary detection = TestUtils.getVocabulary(v3api, sessionToken, "DETECTION"); + // THEN + assertNotNull(detection); + } + + +} diff --git a/openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportVocabularyTypesTest.java b/openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportVocabularyTypesTest.java index 4a8f9088f44..9ebd457bd8e 100644 --- a/openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportVocabularyTypesTest.java +++ b/openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportVocabularyTypesTest.java @@ -75,7 +75,6 @@ public class ImportVocabularyTypesTest extends AbstractImportTest { String f = ImportVocabularyTypesTest.class.getName().replace(".", "/"); FILES_DIR = f.substring(0, f.length() - ImportVocabularyTypesTest.class.getSimpleName().length()) + "/test_files/"; - } @BeforeMethod diff --git a/openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/TestUtils.java b/openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/TestUtils.java index 8991380e794..f81328e301b 100644 --- a/openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/TestUtils.java +++ b/openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/TestUtils.java @@ -9,6 +9,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; import org.apache.commons.io.IOUtils; @@ -53,58 +54,51 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.id.VocabularyPermId; import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.search.VocabularySearchCriteria; import ch.ethz.sis.openbis.generic.server.asapi.v3.IApplicationServerInternalApi; -public class TestUtils -{ +public class TestUtils { private static final String TEST_XLS = "TEST-XLS"; private static final String XLS_NAME = "xls_name"; private static final String UPDATE_MODE = "update_mode"; - public static final String XLS_PARAM = "xls"; + private static final String XLS_PARAM = "xls"; - public static final String SCRIPTS_PARAM = "scripts"; + public static final String CSV_PARAM = "csv"; - public static final String XLS_IMPORT_API = "xls-import-api"; + private static final String SCRIPTS_PARAM = "scripts"; - static Vocabulary getVocabulary(IApplicationServerInternalApi v3api, String sessionToken, String code) - { + private static final String XLS_IMPORT_API = "xls-import-api"; + + static Vocabulary getVocabulary(IApplicationServerInternalApi v3api, String sessionToken, String code) { VocabularySearchCriteria criteria = new VocabularySearchCriteria(); criteria.withId().thatEquals(new VocabularyPermId(code)); - VocabularyFetchOptions fo = new VocabularyFetchOptions(); fo.withTerms(); SearchResult<Vocabulary> result = v3api.searchVocabularies(sessionToken, criteria, fo); - if (result.getObjects().size() > 0) - { + if (result.getObjects().size() > 0) { return result.getObjects().get(0); - } else - { + } else { return null; } } - static List<Vocabulary> getAllVocabularies(IApplicationServerInternalApi v3api, String sessionToken) - { + static List<Vocabulary> getAllVocabularies(IApplicationServerInternalApi v3api, String sessionToken) { VocabularySearchCriteria criteria = new VocabularySearchCriteria(); VocabularyFetchOptions fo = new VocabularyFetchOptions(); fo.withTerms(); SearchResult<Vocabulary> result = v3api.searchVocabularies(sessionToken, criteria, fo); - if (result.getObjects().size() > 0) - { + if (result.getObjects().size() > 0) { return result.getObjects(); - } else - { + } else { return null; } } - static SampleType getSampleType(IApplicationServerInternalApi v3api, String sessionToken, String code) - { + static SampleType getSampleType(IApplicationServerInternalApi v3api, String sessionToken, String code) { SampleTypeSearchCriteria criteria = new SampleTypeSearchCriteria(); criteria.withCode().thatEquals(code); @@ -116,17 +110,14 @@ public class TestUtils SearchResult<SampleType> result = v3api.searchSampleTypes(sessionToken, criteria, fo); - if (result.getObjects().size() > 0) - { + if (result.getObjects().size() > 0) { return result.getObjects().get(0); - } else - { + } else { return null; } } - static ExperimentType getExperimentType(IApplicationServerInternalApi v3api, String sessionToken, String code) - { + static ExperimentType getExperimentType(IApplicationServerInternalApi v3api, String sessionToken, String code) { ExperimentTypeSearchCriteria criteria = new ExperimentTypeSearchCriteria(); criteria.withCode().thatEquals(code); @@ -138,17 +129,14 @@ public class TestUtils SearchResult<ExperimentType> result = v3api.searchExperimentTypes(sessionToken, criteria, fo); - if (result.getObjects().size() > 0) - { + if (result.getObjects().size() > 0) { return result.getObjects().get(0); - } else - { + } else { return null; } } - static DataSetType getDatasetType(IApplicationServerInternalApi v3api, String sessionToken, String code) - { + static DataSetType getDatasetType(IApplicationServerInternalApi v3api, String sessionToken, String code) { DataSetTypeSearchCriteria criteria = new DataSetTypeSearchCriteria(); criteria.withCode().thatEquals(code); @@ -160,17 +148,14 @@ public class TestUtils SearchResult<DataSetType> result = v3api.searchDataSetTypes(sessionToken, criteria, fo); - if (result.getObjects().size() > 0) - { + if (result.getObjects().size() > 0) { return result.getObjects().get(0); - } else - { + } else { return null; } } - static PropertyType getPropertyType(IApplicationServerInternalApi v3api, String sessionToken, String code) - { + static PropertyType getPropertyType(IApplicationServerInternalApi v3api, String sessionToken, String code) { PropertyTypeSearchCriteria criteria = new PropertyTypeSearchCriteria(); criteria.withCode().thatEquals(code); @@ -179,17 +164,14 @@ public class TestUtils SearchResult<PropertyType> result = v3api.searchPropertyTypes(sessionToken, criteria, fo); - if (result.getObjects().size() > 0) - { + if (result.getObjects().size() > 0) { return result.getObjects().get(0); - } else - { + } else { return null; } } - static Space getSpace(IApplicationServerInternalApi v3api, String sessionToken, String code) - { + static Space getSpace(IApplicationServerInternalApi v3api, String sessionToken, String code) { SpaceSearchCriteria criteria = new SpaceSearchCriteria(); criteria.withCode().thatEquals(code); @@ -197,17 +179,14 @@ public class TestUtils SearchResult<Space> result = v3api.searchSpaces(sessionToken, criteria, fo); - if (result.getObjects().size() > 0) - { + if (result.getObjects().size() > 0) { return result.getObjects().get(0); - } else - { + } else { return null; } } - static Project getProject(IApplicationServerInternalApi v3api, String sessionToken, String code) - { + static Project getProject(IApplicationServerInternalApi v3api, String sessionToken, String code) { ProjectSearchCriteria criteria = new ProjectSearchCriteria(); criteria.withCode().thatEquals(code); @@ -216,18 +195,15 @@ public class TestUtils SearchResult<Project> result = v3api.searchProjects(sessionToken, criteria, fo); - if (result.getObjects().size() > 0) - { + if (result.getObjects().size() > 0) { return result.getObjects().get(0); - } else - { + } else { return null; } } static Experiment getExperiment(IApplicationServerInternalApi v3api, String sessionToken, String experimentCode, String projectCode, - String spaceCode) - { + String spaceCode) { List<IExperimentId> ids = new ArrayList<>(); ids.add(new ExperimentIdentifier(spaceCode, projectCode, experimentCode)); @@ -238,33 +214,28 @@ public class TestUtils List<Experiment> result = v3api.getExperiments(sessionToken, ids, fo).values().stream().collect(Collectors.toList()); - if (result.size() > 0) - { + if (result.size() > 0) { return result.get(0); - } else - { + } else { return null; } } - static Sample getSample(IApplicationServerInternalApi v3api, String sessionToken, String sampleCode, String spaceCode) - { + static Sample getSample(IApplicationServerInternalApi v3api, String sessionToken, String sampleCode, String spaceCode) { List<ISampleId> ids = new ArrayList<>(); ids.add(new SampleIdentifier(spaceCode, null, null, sampleCode)); return getSamples(v3api, sessionToken, ids); } - static Sample getSampleByPermId(IApplicationServerInternalApi v3api, String sessionToken, String permId) - { + static Sample getSampleByPermId(IApplicationServerInternalApi v3api, String sessionToken, String permId) { List<ISampleId> ids = new ArrayList<>(); ids.add(new SamplePermId(permId)); return getSamples(v3api, sessionToken, ids); } - private static Sample getSamples(IApplicationServerInternalApi v3api, String sessionToken, List<ISampleId> ids) - { + private static Sample getSamples(IApplicationServerInternalApi v3api, String sessionToken, List<ISampleId> ids) { SampleFetchOptions fo = new SampleFetchOptions(); SampleFetchOptions childrenFo = fo.withChildren(); childrenFo.withSpace(); @@ -280,20 +251,16 @@ public class TestUtils List<Sample> result = v3api.getSamples(sessionToken, ids, fo).values().stream().collect(Collectors.toList()); - if (result.size() > 0) - { + if (result.size() > 0) { return result.get(0); - } else - { + } else { return null; } } - static String createFrom(IApplicationServerInternalApi v3api, String sessionToken, Path... xls_paths) throws IOException - { + static String createFrom(IApplicationServerInternalApi v3api, String sessionToken, Path... xls_paths) throws IOException { List<byte[]> excels = new ArrayList<>(); - for (Path xls_path : xls_paths) - { + for (Path xls_path : xls_paths) { byte[] xls = readData(xls_path); excels.add(xls); } @@ -304,18 +271,28 @@ public class TestUtils return (String) v3api.executeCustomASService(sessionToken, new CustomASServiceCode(XLS_IMPORT_API), options); } + static String createFromCsv(IApplicationServerInternalApi v3api, String sessionToken, Path... csv_paths) throws IOException { + List<byte[]> csvs = new ArrayList<>(); + for (Path csv_path : csv_paths) { + byte[] csv = readData(csv_path); + csvs.add(csv); + } + CustomASServiceExecutionOptions options = new CustomASServiceExecutionOptions(); + options.withParameter(CSV_PARAM, csvs); + options.withParameter(UPDATE_MODE, UpdateMode.IGNORE_EXISTING.name()); + options.withParameter(XLS_NAME, TEST_XLS); + return (String) v3api.executeCustomASService(sessionToken, new CustomASServiceCode(XLS_IMPORT_API), options); + } + static String createFrom(IApplicationServerInternalApi v3api, String sessionToken, Map<String, String> scripts, Path... xls_paths) - throws IOException - { + throws IOException { return TestUtils.createFrom(v3api, sessionToken, scripts, UpdateMode.IGNORE_EXISTING, xls_paths); } static String createFrom(IApplicationServerInternalApi v3api, String sessionToken, Map<String, String> scripts, UpdateMode updateMode, - Path... xls_paths) throws IOException - { + Path... xls_paths) throws IOException { List<byte[]> excels = new ArrayList<>(); - for (Path xls_path : xls_paths) - { + for (Path xls_path : xls_paths) { byte[] xls = readData(xls_path); excels.add(xls); } @@ -327,18 +304,15 @@ public class TestUtils return (String) v3api.executeCustomASService(sessionToken, new CustomASServiceCode(XLS_IMPORT_API), options); } - static String getValidationScript() - { + static String getValidationScript() { return "def validate(entity, isNew):\n if isNew:\n return"; } - static String getDynamicScript() - { + static String getDynamicScript() { return "def calculate():\n return 1"; } - static Map<String, String> getValidationPluginMap() - { + static Map<String, String> getValidationPluginMap() { String dynamicScriptString = getValidationScript(); Map<String, String> scriptsMap = new HashMap<>(); scriptsMap.put("valid.py", dynamicScriptString); @@ -346,8 +320,7 @@ public class TestUtils return scriptsMap; } - static Map<String, String> getDynamicPluginMap() - { + static Map<String, String> getDynamicPluginMap() { String dynamicScriptString = getDynamicScript(); Map<String, String> scriptsMap = new HashMap<>(); scriptsMap.put("dynamic/dynamic.py", dynamicScriptString); @@ -355,8 +328,7 @@ public class TestUtils return scriptsMap; } - static String extractSamplePermIdFromResults(String result) - { + static String extractSamplePermIdFromResults(String result) { // Note this will work only if we created single sample!! String permId = result.substring(result.indexOf("CreateSamplesOperationResult") + "CreateSamplesOperationResult".length()); permId = StringUtils.strip(permId, "[]"); @@ -364,15 +336,13 @@ public class TestUtils } static List<PropertyAssignment> extractAndSortPropertyAssignmentsPerGivenPropertyName(IEntityType rawData, List<String> propertyNames) - throws Exception - { + throws Exception { List<PropertyAssignment> propertyAssignments = rawData.getPropertyAssignments(); List<PropertyAssignment> sortedPropertyAssignments = propertyNames.stream().map(propertyName -> { return propertyAssignments.stream().filter(prop -> prop.getPropertyType().getPermId().toString().equals(propertyName)).findFirst().get(); }).collect(Collectors.toList()); - if (sortedPropertyAssignments.stream().anyMatch(property -> property == null)) - { + if (sortedPropertyAssignments.stream().anyMatch(Objects::isNull)) { throw new Exception("Some properties are missing" + "\nFollowing properties are expected " + Arrays.toString(propertyNames.toArray()) + "\n Available properties are: " + Arrays.toString(propertyAssignments.toArray())); @@ -381,21 +351,12 @@ public class TestUtils return sortedPropertyAssignments; } - private static byte[] readData(Path xls_path) throws IOException - { + private static byte[] readData(Path xls_path) throws IOException { String path = xls_path.toString(); - InputStream resourceAsStream = TestUtils.class.getClassLoader().getResourceAsStream(path); - try - { + try (InputStream resourceAsStream = TestUtils.class.getClassLoader().getResourceAsStream(path)) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); IOUtils.copy(resourceAsStream, byteArrayOutputStream); return byteArrayOutputStream.toByteArray(); - } finally - { - if (resourceAsStream != null) - { - resourceAsStream.close(); - } } } diff --git a/openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/csv/types.csv b/openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/csv/types.csv new file mode 100644 index 00000000000..f316aaed6c9 --- /dev/null +++ b/openbis_standard_technologies/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/csv/types.csv @@ -0,0 +1,7 @@ +VOCABULARY_TYPE,,,,,,,,,,,,,,,,, +Version,Code,Description,,,,,,,,,,,,,,, +225,DETECTION,Protein detection system,,,,,,,,,,,,,,, +Version,Code,Label,Description,,,,,,,,,,,,,, +225,HRP,horseradish peroxydase,The antibody is conjugated with the horseradish peroxydase,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,, -- GitLab