diff --git a/api-openbis-python3-pybis/src/python/pybis/definitions.py b/api-openbis-python3-pybis/src/python/pybis/definitions.py index 25c31e6656e2ec4425557f4fde6a81ddd9c59a78..035130bb4d9d74fb2661818782a0153bbdf848a1 100644 --- a/api-openbis-python3-pybis/src/python/pybis/definitions.py +++ b/api-openbis-python3-pybis/src/python/pybis/definitions.py @@ -167,6 +167,11 @@ def openbis_definitions(entity): "MATERIAL", "HYPERLINK", "XML", + "ARRAY_INTEGER", + "ARRAY_REAL", + "ARRAY_STRING", + "ARRAY_TIMESTAMP", + "JSON" ], "identifier": "typeId", }, diff --git a/api-openbis-python3-pybis/src/python/pybis/entity_type.py b/api-openbis-python3-pybis/src/python/pybis/entity_type.py index 139d3a9d0cf8ac4f009f41b2b3712c379c780172..a17be6eb6b3a05c1d4ed396e581f7be514776655 100644 --- a/api-openbis-python3-pybis/src/python/pybis/entity_type.py +++ b/api-openbis-python3-pybis/src/python/pybis/entity_type.py @@ -12,29 +12,22 @@ # See the License for the specific language governing permissions and # limitations under the License. # -from tabulate import tabulate -from texttable import Texttable from pandas import DataFrame + +from .definitions import ( + get_method_for_entity, + get_type_for_entity, + get_definition_for_entity, +) from .openbis_object import OpenBisObject +from .semantic_annotation import SemanticAnnotation from .things import Things from .utils import ( - check_datatype, - split_identifier, format_timestamp, - is_identifier, - is_permid, - nvl, - extract_permid, extract_code, extract_name, VERBOSE, ) -from .definitions import ( - get_method_for_entity, - get_type_for_entity, - get_definition_for_entity, -) -from .semantic_annotation import SemanticAnnotation class EntityType: @@ -193,7 +186,7 @@ class EntityType: # assign plugin if plugin is not None: plugin_obj = self.openbis.get_plugin(plugin) - new_assignment["plugin"] = plugin_obj.name + new_assignment["plugin"] = plugin_obj.permId request = self._get_request_for_pa(new_assignment, "Add") try: @@ -229,11 +222,11 @@ class EntityType: } request = self._get_request_for_pa(items, "Remove", force) resp = self.openbis._post_request(self.openbis.as_v3, request) - if not resp and VERBOSE: + if not resp: new_data = self._get_method(self.permId, only_data=True) self._set_entity_data(new_data) - - print(f"Property {property_type} revoked from {self.permId}") + if VERBOSE: + print(f"Property {property_type} revoked from {self.permId}") def _get_request_for_pa(self, items, item_action, force=False): diff --git a/api-openbis-python3-pybis/src/python/pybis/experiment.py b/api-openbis-python3-pybis/src/python/pybis/experiment.py index f078aef9b9b962d100a80dfe69c687c7f7a45d27..14eba9723d430e8b495a4c884a6ea0f4706ccdd6 100644 --- a/api-openbis-python3-pybis/src/python/pybis/experiment.py +++ b/api-openbis-python3-pybis/src/python/pybis/experiment.py @@ -12,11 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # -from .property import PropertyHolder -from .attribute import AttrHolder from .openbis_object import OpenBisObject -from .definitions import openbis_definitions -from .utils import VERBOSE class Experiment( @@ -30,8 +26,11 @@ class Experiment( self.a(data) self.__dict__["data"] = data - # put the properties in the self.p namespace (without checking them) + # put the properties in the self.p namespace for key, value in data["properties"].items(): + data_type = self.p._property_names[key.lower()]['dataType'] + if data_type in ("ARRAY_INTEGER", "ARRAY_REAL", "ARRAY_STRING", "ARRAY_TIMESTAMP"): + value = self.formatter.to_array(data_type, value) self.p.__dict__[key.lower()] = value def __str__(self): diff --git a/api-openbis-python3-pybis/src/python/pybis/openbis_object.py b/api-openbis-python3-pybis/src/python/pybis/openbis_object.py index 5afb398015beec585ff177b47a25ea1a3af9b000..d351da7485764e7616f76691ce64798b8cd1b7bb 100644 --- a/api-openbis-python3-pybis/src/python/pybis/openbis_object.py +++ b/api-openbis-python3-pybis/src/python/pybis/openbis_object.py @@ -71,6 +71,9 @@ class OpenBisObject: # put the properties in the self.p namespace (without checking them) if "properties" in data: for key, value in data["properties"].items(): + data_type = self.p._property_names[key.lower()]['dataType'] + if data_type in ("ARRAY_INTEGER", "ARRAY_REAL", "ARRAY_STRING", "ARRAY_TIMESTAMP"): + value = self.formatter.to_array(data_type, value) self.p.__dict__[key.lower()] = value # object is already saved to openBIS, so it is not new anymore diff --git a/api-openbis-python3-pybis/src/python/pybis/property.py b/api-openbis-python3-pybis/src/python/pybis/property.py index c792454a77b5dc4c79ba51303d83457aac5c6954..54b8577de72f50f76309aa0d3e8baa7af5f56698 100644 --- a/api-openbis-python3-pybis/src/python/pybis/property.py +++ b/api-openbis-python3-pybis/src/python/pybis/property.py @@ -13,14 +13,9 @@ # limitations under the License. # from tabulate import tabulate -from texttable import Texttable + from pybis.utils import ( check_datatype, - split_identifier, - format_timestamp, - is_identifier, - is_permid, - nvl, ) @@ -147,7 +142,7 @@ class PropertyHolder: raise ValueError( f"Value for attribute «{name}» must be one of these terms: {', '.join(terms.df['code'].values)}" ) - elif data_type in ("INTEGER", "BOOLEAN", "VARCHAR"): + elif data_type in ("INTEGER", "BOOLEAN", "VARCHAR", "ARRAY_INTEGER", "ARRAY_REAL", "ARRAY_STRING", "ARRAY_TIMESTAMP"): if not check_datatype(data_type, value): raise ValueError(f"Value must be of type {data_type}") self.__dict__[name] = value diff --git a/api-openbis-python3-pybis/src/python/pybis/property_reformatter.py b/api-openbis-python3-pybis/src/python/pybis/property_reformatter.py index 59739cd644f6dd70d738057f362c9a4fc6a3f46b..5257595ca8ddcdc129821f284f645104795a044a 100644 --- a/api-openbis-python3-pybis/src/python/pybis/property_reformatter.py +++ b/api-openbis-python3-pybis/src/python/pybis/property_reformatter.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # +import re from datetime import datetime import pandas as pd @@ -44,9 +45,15 @@ class PropertyReformatter: raise ValueError('properties can not be None!') for key, value in properties.items(): + if value is None: + continue property_type = self.openbis.get_property_type(key) if property_type.dataType == 'TIMESTAMP': properties[key] = self._format_timestamp(value) + elif property_type.dataType == 'ARRAY_TIMESTAMP': + properties[key] = ",".join([self._format_timestamp(x) for x in value]) + elif property_type.dataType.startswith('ARRAY'): + properties[key] = ",".join(map(str, value)) return properties @@ -60,3 +67,17 @@ class PropertyReformatter: print( f'WARNING: "{value}" is not of any OpenBis supported datetime formats. Reformatting to "{result}"') return result + + def to_array(self, data_type, prop_value): + if prop_value is None or prop_value == "": + return [] + result = [] + if data_type == "ARRAY_INTEGER": + result = [int(x.strip()) for x in prop_value.split(',')] + elif data_type == "ARRAY_REAL": + result = [float(x.strip()) for x in prop_value.split(',')] + elif data_type == "ARRAY_STRING": + result = [x.strip() for x in re.split(r"(?<!\\),", prop_value)] + elif data_type == "ARRAY_TIMESTAMP": + result = [x.strip() for x in prop_value.split(',')] + return result diff --git a/api-openbis-python3-pybis/src/python/pybis/pybis.py b/api-openbis-python3-pybis/src/python/pybis/pybis.py index a48ba586b9a59bda23525c47b79d161dadf9f91e..3cb5587b4de42e51cdcc347a3c338be1d1f6be9a 100644 --- a/api-openbis-python3-pybis/src/python/pybis/pybis.py +++ b/api-openbis-python3-pybis/src/python/pybis/pybis.py @@ -1292,7 +1292,6 @@ class Openbis: if resp.ok: resp = resp.json() if "error" in resp: - # print(full_url) print(json.dumps(request)) raise ValueError(resp["error"]["message"]) elif "result" in resp: @@ -1300,7 +1299,8 @@ class Openbis: else: raise ValueError("request did not return either result nor error") else: - raise ValueError("general error while performing post request") + raise ValueError( + f"general error while performing post request. {resp.status_code}:{resp.reason}") def logout(self): """Log out of openBIS. After logout, the session token is no longer valid.""" diff --git a/api-openbis-python3-pybis/src/python/pybis/sample.py b/api-openbis-python3-pybis/src/python/pybis/sample.py index 5514a7f6821d71de91e62fd10c0cc3426c62a991..be92088af1c4883088d7edd9235985c4b7fe21a1 100644 --- a/api-openbis-python3-pybis/src/python/pybis/sample.py +++ b/api-openbis-python3-pybis/src/python/pybis/sample.py @@ -90,8 +90,11 @@ class Sample(OpenBisObject, entity="sample", single_item_method_name="get_sample self.a(data) self.__dict__["data"] = data - # put the properties in the self.p namespace (without checking them) + # put the properties in the self.p namespace for key, value in data["properties"].items(): + data_type = self.p._property_names[key.lower()]['dataType'] + if data_type in ("ARRAY_INTEGER", "ARRAY_REAL", "ARRAY_STRING", "ARRAY_TIMESTAMP"): + value = self.formatter.to_array(data_type, value) self.p.__dict__[key.lower()] = value def __dir__(self): diff --git a/api-openbis-python3-pybis/src/python/pybis/utils.py b/api-openbis-python3-pybis/src/python/pybis/utils.py index 9dff312fda730e37d6670547d7ea735bd3580c32..11bfb5d8742b0b8083f6084fcff6ed61b1735e06 100644 --- a/api-openbis-python3-pybis/src/python/pybis/utils.py +++ b/api-openbis-python3-pybis/src/python/pybis/utils.py @@ -12,9 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # -from datetime import datetime -from pathlib import Path import re +from datetime import datetime # display messages when in a interactive context (IPython or Jupyter) try: @@ -128,6 +127,8 @@ def check_datatype(type_name, value): return isinstance(value, bool) if type_name == "VARCHAR": return isinstance(value, str) + if type_name is not None and type_name.startswith("ARRAY"): + return isinstance(value, list) return True