From 2ded4be4582aac3372e56e9008957e25eec9c087 Mon Sep 17 00:00:00 2001 From: alaskowski <alaskowski@ethz.ch> Date: Thu, 9 Nov 2023 17:09:11 +0100 Subject: [PATCH] BIS-716: Added simple data model and validator for imaging_data_set --- .../imaging/1/as/initialize-master-data.py | 73 ++++++++ .../1/as/master-data/imaging-data-model.xls | Bin 0 -> 23552 bytes .../imaging_dataset_config_validation.py | 163 +++++++++++++++++- 3 files changed, 231 insertions(+), 5 deletions(-) create mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/as/initialize-master-data.py create mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/as/master-data/imaging-data-model.xls diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/as/initialize-master-data.py b/core-plugin-openbis/dist/core-plugins/imaging/1/as/initialize-master-data.py new file mode 100644 index 00000000000..e1ed0ce1fa3 --- /dev/null +++ b/core-plugin-openbis/dist/core-plugins/imaging/1/as/initialize-master-data.py @@ -0,0 +1,73 @@ +# +# Copyright 2014 ETH Zuerich, Scientific IT Services +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# MasterDataRegistrationTransaction Class +from ch.ethz.sis.openbis.generic.server.asapi.v3 import ApplicationServerApi +from ch.systemsx.cisd.openbis.generic.server import CommonServiceProvider +from ch.ethz.sis.openbis.generic.asapi.v3.dto.service.id import CustomASServiceCode +from ch.ethz.sis.openbis.generic.asapi.v3.dto.service import CustomASServiceExecutionOptions +from ch.systemsx.cisd.openbis.generic.server.jython.api.v1.impl import MasterDataRegistrationHelper +import sys + +helper = MasterDataRegistrationHelper(sys.path) +api = CommonServiceProvider.getApplicationContext().getBean(ApplicationServerApi.INTERNAL_SERVICE_NAME) +sessionToken = api.loginAsSystem() +props = CustomASServiceExecutionOptions().withParameter('xls', helper.listXlsByteArrays()) \ + .withParameter('method', 'import').withParameter('zip', False).withParameter('xls_name', 'IMAGING').withParameter('update_mode', 'UPDATE_IF_EXISTS') \ + .withParameter('scripts', helper.getAllScripts()) +result = api.executeCustomASService(sessionToken, CustomASServiceCode("xls-import"), props) +api.logout(sessionToken) +print("======================== imaging-master-data xls ingestion result ========================") +print(result) +print("======================== imaging-data xls ingestion result ========================") + + + +# from ch.ethz.sis.openbis.generic.server.asapi.v3 import ApplicationServerApi +# from ch.systemsx.cisd.openbis.generic.server import CommonServiceProvider +# from ch.ethz.sis.openbis.generic.asapi.v3.dto.service.id import CustomASServiceCode +# from ch.ethz.sis.openbis.generic.asapi.v3.dto.service import CustomASServiceExecutionOptions +# from ch.systemsx.cisd.openbis.generic.server.jython.api.v1.impl import MasterDataRegistrationHelper +# import sys +# +# from ch.systemsx.cisd.openbis.generic.server.hotfix import ELNFixes +# from ch.systemsx.cisd.openbis.generic.server.hotfix import ELNAnnotationsMigration +# from ch.systemsx.cisd.openbis.generic.server.hotfix import ELNCollectionTypeMigration +# +# api = CommonServiceProvider.getApplicationContext().getBean(ApplicationServerApi.INTERNAL_SERVICE_NAME) +# sessionToken = api.loginAsSystem() +# +# if ELNFixes.isELNInstalled(): +# ELNFixes.beforeUpgrade(sessionToken) +# ELNAnnotationsMigration.beforeUpgrade(sessionToken) +# ELNCollectionTypeMigration.beforeUpgrade(sessionToken) +# +# helper = MasterDataRegistrationHelper(sys.path) +# props = CustomASServiceExecutionOptions().withParameter('xls', helper.getByteArray("common-data-model.xls"))\ +# .withParameter('method', 'import').withParameter('zip', False).withParameter('xls_name', 'ELN-LIMS').withParameter('update_mode', 'UPDATE_IF_EXISTS')\ +# .withParameter('scripts', helper.getAllScripts()) +# result = api.executeCustomASService(sessionToken, CustomASServiceCode("xls-import"), props) +# +# if not ELNFixes.isMultiGroup(): +# props = CustomASServiceExecutionOptions().withParameter('xls', helper.getByteArray("single-group-data-model.xls"))\ +# .withParameter('method', 'import').withParameter('zip', False).withParameter('xls_name', 'ELN-LIMS').withParameter('update_mode', 'UPDATE_IF_EXISTS')\ +# .withParameter('scripts', helper.getAllScripts()) +# result = api.executeCustomASService(sessionToken, CustomASServiceCode("xls-import"), props) +# +# ELNCollectionTypeMigration.afterUpgrade() +# api.logout(sessionToken) +# print("======================== master-data xls ingestion result ========================") +# print(result) +# print("======================== master-data xls ingestion result ========================") diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/as/master-data/imaging-data-model.xls b/core-plugin-openbis/dist/core-plugins/imaging/1/as/master-data/imaging-data-model.xls new file mode 100644 index 0000000000000000000000000000000000000000..8f88765f4618a3462bf4118c977d56eb9f621c5d GIT binary patch literal 23552 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 L{QuSe>-PT#nLi{N literal 0 HcmV?d00001 diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/as/master-data/scripts/imaging_dataset_config_validation.py b/core-plugin-openbis/dist/core-plugins/imaging/1/as/master-data/scripts/imaging_dataset_config_validation.py index 8f06d3e3744..6766c2ff211 100644 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/as/master-data/scripts/imaging_dataset_config_validation.py +++ b/core-plugin-openbis/dist/core-plugins/imaging/1/as/master-data/scripts/imaging_dataset_config_validation.py @@ -13,17 +13,170 @@ # limitations under the License. # +import json + + +def assert_control(control_config): + if not control_config: + return True, '' + obligatory_tags = ['@type', 'label', 'type'] + for tag in obligatory_tags: + if tag not in control_config: + return False, tag+': is missing!' + if control_config[tag] is None: + return False, tag+': can not be empty!' + + list_tags = ['values', 'range', 'speeds', 'visibility'] + for list_tag in list_tags: + if list_tag in control_config and control_config[list_tag] is not None and not isinstance(control_config[list_tag], list): + return False, list_tag+': must be a list or null!' + + boolean_tags = ['playable', 'multiselect'] + for boolean_tag in boolean_tags: + if boolean_tag in control_config and control_config[boolean_tag] is not None and not isinstance(control_config[boolean_tag], bool): + return False, boolean_tag+': must be a boolean or empty!' + + if 'visibility' in control_config and control_config['visibility'] is not None: + visibility = control_config['visibility'] + for vis in visibility: + tags = ['label', 'values'] + all_tags = tags + ['range', 'unit'] + for tag in ['label', 'values']: + if tag not in vis: + return False, 'visibility->'+tag+': is missing!' + if vis[tag] is None: + return False, 'visibility->'+tag+': can not be empty!' + + for tag in ['values', 'range']: + if tag in vis and vis[tag] is not None and not isinstance(vis[tag], list): + return False, 'visibility->'+tag+': must be a list!' + + if 'metadata' in control_config and control_config['metadata'] is not None and not isinstance(control_config['metadata'], dict): + return False, '->metadata: must be a dictionary or null!' + + return True, '' + + +def assert_config(json_config): + if 'config' in json_config: + config = json_config['config'] + obligatory_tags = ['@type', 'adaptor', 'version', 'playable', 'exports', 'inputs'] + for tag in obligatory_tags: + if tag not in config: + return False, 'config->' + tag + ': is missing!' + if config[tag] is None: + return False, 'config->' + tag + ': can not be empty!' + + if config['adaptor'].strip() == '': + return False, 'config->adaptor: can not be blank!' + + list_tags = ['speeds', 'resolutions', 'exports', 'inputs'] + for list_tag in list_tags: + if list_tag in config and config[list_tag] is not None and not isinstance(config[list_tag], list): + return False, '\''+list_tag+'\' must be a list or null!' + + if not isinstance(config['playable'], bool): + return False, 'config->playable: must be a boolean!' + + for control in config['exports']: + result, err = assert_control(control) + if not result: + return result, 'config->exports->' + err + + for control in config['inputs']: + result, err = assert_control(control) + if not result: + return result, 'config->inputs->' + err + + if 'metadata' in config and config['metadata'] is not None and not isinstance(config['metadata'], dict): + return False, 'config->metadata: must be a dictionary or null!' + else: + return False, 'Missing \'config\' tag in configuration!' + return True, '' + + +def assert_preview(preview_config): + obligatory_tags = ['@type', 'format', 'show'] + for tag in obligatory_tags: + if tag not in config: + return False, tag + ': is missing!' + if config[tag] is None: + return False, tag + ': can not be empty!' + + if not isinstance(preview_config['show'], bool): + return False, 'show: must be boolean!' + + if not isinstance(preview_config['format'], str): + return False, 'format: must be string!' + + if 'bytes' in preview_config and preview_config['bytes'] is not None and not isinstance(preview_config['bytes'], str): + return False, 'bytes: must be a base64 encoded string or null!' + + if 'metadata' in preview_config and preview_config['metadata'] is not None and not isinstance(preview_config['metadata'], dict): + return False, 'metadata: must be a dictionary or null!' + + if 'config' in preview_config and preview_config['config'] is not None and not isinstance(preview_config['config'], dict): + return False, 'config: must be a dictionary or null!' + + return True, '' + + +def assert_images(json_config): + if 'images' in json_config: + images = json_config['images'] + if images is None: + return False, '\'images\' tag can not be null!' + if not isinstance(images, list): + return False, '\'images\' tag must be a list!' + + for image in images: + obligatory_tags = ['@type'] + for tag in obligatory_tags: + if tag not in image: + return False, 'images->' + tag + ': missing tag!' + if image[tag] is None: + return False, 'images->' + tag + ': can not be empty!' + + if 'metadata' in image and image['metadata'] is not None and not isinstance(image['metadata'], dict): + return False, 'images->metadata: must be a dictionary or null!' + + if 'previews' in image and image['previews'] is not None and not isinstance(image['previews'], list): + return False, 'images->previews: must be a list or null!' + + for preview in image['previews']: + res, err = assert_preview(preview) + if not res: + return result, 'images->previews->' + err + + else: + return False, 'Missing \'images\' tag in configuration!' + return True, '' + def get_rendered_property(entity, property): - value = entity.property(property) - if value is not None: - return value.renderedValue() + properties = entity.externalDataPE().getProperties() + for prop in properties: + etpt = prop.getEntityTypePropertyType() + pt = etpt.getPropertyType() + code = pt.getCode() + if code == property: + return prop.tryGetUntypedValue() + return None def validate(entity, is_new): imaging_dataset_config = get_rendered_property(entity, "$IMAGING_DATA_CONFIG") if imaging_dataset_config is None or imaging_dataset_config == "": return "Imaging dataset config can not be empty!" + elif "test_validation_failure" in imaging_dataset_config: + return "Imaging dataset config validation failure!" else: - # TODO add deserialization and validation of particular fields - pass + + try: + config = json.loads(imaging_dataset_config) + except Exception as e: + return "Could not parse JSON: " + e + + result, err = assert_config(config) + if not result: + return err -- GitLab