Skip to content
Snippets Groups Projects
pybis.py 171 KiB
Newer Older
  • Learn to ignore specific revisions
  • Swen Vermeul's avatar
    Swen Vermeul committed
                start_with=start_with,
                count=count,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                totalCount=resp.get("totalCount"),
    
                df_initializer=create_data_frame,
    
        def get_space(self, code, only_data=False, use_cache=True):
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            """Returns a Space object for a given identifier."""
    
            space = (
                not only_data
                and use_cache
                and self._object_cache(entity="space", code=code)
            )
    
            fetchopts = {"@type": "as.dto.space.fetchoptions.SpaceFetchOptions"}
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            for option in ["registrator"]:
    
                fetchopts[option] = fetch_option[option]
    
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            method = get_method_for_entity("space", "get")
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                "method": method,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    [{"permId": code, "@type": "as.dto.space.id.SpacePermId"}],
                    fetchopts,
    
            resp = self._post_request(self.as_v3, request)
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            if len(resp) == 0:
    
                raise ValueError("No such space: %s" % code)
    
            for permid in resp:
                if only_data:
                    return resp[permid]
                else:
    
                    space = Space(self, data=resp[permid])
                    if self.use_cache:
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                        self._object_cache(entity="space", code=code, value=space)
    
    Swen Vermeul's avatar
    Swen Vermeul committed
        def get_samples(
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            self,
            identifier=None,
            code=None,
            permId=None,
            space=None,
            project=None,
            experiment=None,
            collection=None,
            type=None,
            start_with=None,
            count=None,
            withParents=None,
            withChildren=None,
            tags=None,
            attrs=None,
            props=None,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            **properties,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
        ):
    
            """Returns a DataFrame of all samples for a given space/project/experiment (or any combination)
    
            type         -- sampleType code or object
            space        -- space code or object
            project      -- project code or object
    
            experiment   -- experiment code or object (can be a list, too)
    
            collection   -- same as above
    
            tags         -- only return samples with the specified tags
    
            where        -- key-value pairs of property values to search for
    
            start_with   -- default=None
            count        -- number of samples that should be fetched. default=None.
    
    
            Include in result list
            ----------------------
    
            withParents  -- the list of parent's permIds in a column 'parents'
            withChildren -- the list of children's permIds in a column 'children'
            attrs        -- list of all desired attributes. Examples:
                            space, project, experiment: just return their identifier
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                            parents, children, components: return a list of their identifiers
    
                            space.code, project.code, experiment.code
                            registrator.email, registrator.firstName
                            type.generatedCodePrefix
            props        -- list of all desired properties. Returns an empty string if
                            a) property is not present
                            b) property is not defined for this sampleType
    
            logger = logging.getLogger("get_samples")
            logger.setLevel(logging.CRITICAL)
    
            logger.addHandler(logging.StreamHandler(sys.stdout))
    
    
            if collection is not None:
                experiment = collection
    
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                crit = _subcriteria_for(identifier, "sample")
                sub_criteria += crit["criteria"]
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(_subcriteria_for(space, "space"))
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(_subcriteria_for(project, "project"))
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(_subcriteria_for(experiment, "experiment"))
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(_subcriteria_for(withParents, "sample", "Parents"))
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(_subcriteria_for(withChildren, "sample", "Children"))
    
            if where:
                if properties is None:
                    properties = where
                else:
                    properties = {**where, **properties}
    
    
            if properties is not None:
                for prop in properties:
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    sub_criteria.append(
                        _subcriteria_for_properties(prop, properties[prop], entity="sample")
                    )
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(_subcriteria_for_code(type, "sampleType"))
    
            if tags:
                sub_criteria.append(_subcriteria_for_tags(tags))
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(
                    _subcriteria_for_code_new(code, "sample", operator="OR")
                )
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(
                    _subcriteria_for_permid_new(permId, "sample", operator="OR")
                )
    
            criteria = {
                "criteria": sub_criteria,
                "@type": "as.dto.sample.search.SampleSearchCriteria",
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                "relation": "SAMPLE",
    
            # build the various fetch options
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            fetchopts = fetch_option["sample"]
            fetchopts["from"] = start_with
            fetchopts["count"] = count
    
            options = [
                "tags",
                "properties",
                "attachments",
                "space",
                "experiment",
                "registrator",
                "modifier",
            ]
    
            if self.get_server_information().project_samples_enabled:
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                options.append("project")
    
            for option in options:
                fetchopts[option] = fetch_option[option]
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                fetchopts["properties"] = fetch_option["properties"]
    
            request = {
                "method": "searchSamples",
    
                "params": [
                    self.token,
                    criteria,
                    fetchopts,
                ],
    
    
            time1 = now()
            logger.debug("get_samples posting request")
    
            resp = self._post_request(self.as_v3, request)
    
            time2 = now()
    
            logger.debug(f"get_samples got response. Delay: {time2 - time1}")
    
            time3 = now()
    
            response = resp["objects"]
            logger.debug(f"get_samples got JSON. Delay: {time3 - time2}")
    
            time4 = now()
    
            logger.debug(f"get_samples after result mapping. Delay: {time4 - time3}")
    
    
            result = self._sample_list_for_response(
                response=response,
                attrs=attrs,
                props=props,
                start_with=start_with,
                count=count,
                totalCount=resp["totalCount"],
                parsed=True,
            )
    
    
            time5 = now()
    
            logger.debug(f"get_samples computed final result. Delay: {time5 - time4}")
            return result
    
    Swen Vermeul's avatar
    Swen Vermeul committed
        get_objects = get_samples  # Alias
    
        def _get_fetchopts_for_attrs(self, attrs=None):
            if attrs is None:
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                if attr.startswith("space"):
                    fetchopts.append("space")
                if attr.startswith("project"):
                    fetchopts.append("project")
                if attr.startswith("experiment"):
                    fetchopts.append("experiment")
                if attr.startswith("sample"):
                    fetchopts.append("sample")
                if attr.startswith("registrator"):
                    fetchopts.append("registrator")
                if attr.startswith("modifier"):
                    fetchopts.append("modifier")
    
    Swen Vermeul's avatar
    Swen Vermeul committed
        def get_experiments(
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            self,
            code=None,
            permId=None,
            type=None,
            space=None,
            project=None,
            start_with=None,
            count=None,
            tags=None,
            is_finished=None,
            attrs=None,
            props=None,
            where=None,
            **properties,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
        ):
    
            """Returns a DataFrame of all samples for a given space/project (or any combination)
    
            Filters:
            --------
            space        -- a space code or a space object
            project      -- a project code or a project object
            tags         -- only experiments with the specified tags
            type         -- a experimentType code
    
            where        -- key-value pairs of property values to search for
    
    
            Paging:
            -------
            start_with   -- default=None
            count        -- number of samples that should be fetched. default=None.
    
            Include:
            --------
            attrs        -- list of all desired attributes. Examples:
                            space, project, experiment: just return their identifier
                            space.code, project.code, experiment.code
                            registrator.email, registrator.firstName
                            type.generatedCodePrefix
            props        -- list of all desired properties. Returns an empty string if
                            a) property is not present
                            b) property is not defined for this sampleType
    
            def extract_attribute(attribute_to_extract):
                def return_attribute(obj):
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    if obj is None:
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                        return ""
                    return obj.get(attribute_to_extract, "")
    
    
                return return_attribute
    
            def extract_space(obj):
                if isinstance(obj, dict):
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    return obj.get("space", {})
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    return ""
    
            sub_criteria = []
            if space:
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(
                    _subcriteria_for(space, "project.space", operator="AND")
                )
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(_subcriteria_for(project, "project", operator="AND"))
    
            if code:
    
                sub_criteria.append(_criteria_for_code(code))
    
                sub_criteria.append(_criteria_for_permId(permId))
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(_subcriteria_for_code(type, "experimentType"))
    
            if tags:
                sub_criteria.append(_subcriteria_for_tags(tags))
            if is_finished is not None:
                sub_criteria.append(_subcriteria_for_is_finished(is_finished))
    
            if where:
                if properties is None:
                    properties = where
                else:
                    properties = {**where, **properties}
    
                sub_criteria.extend(
                    list(
                        map(
                            lambda prop: _subcriteria_for_properties(
                                prop, properties[prop], entity="experiment"
                            ),
                            properties,
                        )
                    )
                )
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            search_criteria = get_search_type_for_entity("experiment")
            search_criteria["criteria"] = sub_criteria
            search_criteria["operator"] = "AND"
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            fetchopts = fetch_option["experiment"]
            fetchopts["from"] = start_with
            fetchopts["count"] = count
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            if attrs is None:
                attrs = []
    
            options = self._get_fetchopts_for_attrs(attrs)
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            for option in ["tags", "properties", "registrator", "modifier"] + options:
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                fetchopts[option] = fetch_option[option]
    
    
            request = {
                "method": "searchExperiments",
    
                "params": [
                    self.token,
                    search_criteria,
                    fetchopts,
                ],
    
            }
            resp = self._post_request(self.as_v3, request)
    
            def create_data_frame(attrs, props, response):
                response = response["objects"]
                parse_jackson(response)
    
                default_attrs = [
                    "identifier",
                    "permId",
                    "type",
                    "registrator",
                    "registrationDate",
                    "modifier",
                    "modificationDate",
                ]
    
                display_attrs = default_attrs + attrs
    
                if props is None:
                    props = []
                else:
                    if isinstance(props, str):
                        props = [props]
    
                if len(response) == 0:
                    for prop in props:
                        if prop == "*":
                            continue
                        display_attrs.append(prop)
                    experiments = DataFrame(columns=display_attrs)
                else:
                    experiments = DataFrame(response)
                    experiments["space"] = experiments["project"].map(extract_space)
                    for attr in attrs:
                        if "." in attr:
                            entity, attribute_to_extract = attr.split(".")
                            experiments[attr] = experiments[entity].map(
                                extract_attribute(attribute_to_extract)
                            )
                    for attr in attrs:
                        # if no dot supplied, just display the code of the space, project or experiment
                        if attr in ["project"]:
    
                            experiments[attr] = experiments[attr].map(
                                extract_nested_identifier
                            )
    
                        if attr in ["space"]:
                            experiments[attr] = experiments[attr].map(extract_code)
    
                    experiments["registrationDate"] = experiments["registrationDate"].map(
                        format_timestamp
                    )
                    experiments["modificationDate"] = experiments["modificationDate"].map(
                        format_timestamp
                    )
                    experiments["project"] = experiments["project"].map(extract_code)
    
                    experiments["registrator"] = experiments["registrator"].map(
                        extract_person
                    )
    
                    experiments["modifier"] = experiments["modifier"].map(extract_person)
                    experiments["identifier"] = experiments["identifier"].map(
                        extract_identifier
                    )
                    experiments["permId"] = experiments["permId"].map(extract_permid)
                    experiments["type"] = experiments["type"].map(extract_code)
    
                    for prop in props:
                        if prop == "*":
                            # include all properties in dataFrame.
                            # expand the dataFrame by adding new columns
                            columns = []
                            for i, experiment in enumerate(response):
    
                                for prop_name, val in experiment.get(
                                    "properties", {}
                                ).items():
    
                                    experiments.loc[i, prop_name.upper()] = val
                                    columns.append(prop_name.upper())
    
                            display_attrs += set(columns)
                            continue
                        else:
                            # property name is provided
                            for i, experiment in enumerate(response):
                                val = experiment.get("properties", {}).get(
                                    prop, ""
                                ) or experiment.get("properties", {}).get(prop.upper(), "")
                                experiments.loc[i, prop.upper()] = val
                            display_attrs.append(prop.upper())
                return experiments[display_attrs]
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                openbis_obj=self,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                entity="experiment",
                identifier_name="identifier",
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                start_with=start_with,
                count=count,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                totalCount=resp.get("totalCount"),
    
                df_initializer=create_data_frame,
    
        get_collections = get_experiments  # Alias
    
    Swen Vermeul's avatar
    Swen Vermeul committed
        def get_datasets(
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            self,
            permId=None,
            code=None,
            type=None,
            withParents=None,
            withChildren=None,
            start_with=None,
            count=None,
            kind=None,
            status=None,
            sample=None,
            experiment=None,
            collection=None,
            project=None,
            space=None,
            tags=None,
            attrs=None,
            props=None,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            **properties,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
        ):
    
            """Returns a DataFrame of all dataSets for a given project/experiment/sample (or any combination)
    
            permId       -- the permId is the unique identifier of a dataSet. A list of permIds can be provided.
            code         -- actually a synonym for the permId of the dataSet.
    
            project      -- a project code or a project object
            experiment   -- an experiment code or an experiment object
            sample       -- a sample code/permId or a sample/object
            collection   -- same as experiment
            tags         -- only return dataSets with the specified tags
            type         -- a dataSetType code
    
            where        -- key-value pairs of property values to search for
    
            start_with   -- default=None
            count        -- number of dataSets that should be fetched. default=None.
    
    
            Include in result list
            ----------------------
    
            withParents  -- the list of parent's permIds in a column 'parents'
            withChildren -- the list of children's permIds in a column 'children'
            attrs        -- list of all desired attributes. Examples:
                            project, experiment, sample: just return their identifier
                            space.code, project.code, experiment.code
                            registrator.email, registrator.firstName
                            type.generatedCodePrefix
            props        -- list of all desired properties. Returns an empty string if
                            a) property is not present
                            b) property is not defined for this dataSetType
            """
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            if "object" in properties:
                sample = properties["object"]
    
            if collection is not None:
                experiment = collection
    
    
            if code or permId:
                if code is None:
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    code = permId
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(
                    _subcriteria_for_code_new(code, "dataSet", operator="OR")
                )
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(_subcriteria_for_code(type, "dataSetType"))
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(_subcriteria_for(withParents, "dataSet", "Parents"))
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(_subcriteria_for(withChildren, "dataSet", "Children"))
    
            if sample:
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(_subcriteria_for(sample, "sample"))
    
            if experiment:
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(_subcriteria_for(experiment, "experiment"))
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            if attrs is None:
                attrs = []
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            if project:
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(_subcriteria_for(project, "experiment.project"))
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(_subcriteria_for(space, "experiment.project.space"))
    
            if tags:
                sub_criteria.append(_subcriteria_for_tags(tags))
    
            if status:
                sub_criteria.append(_subcriteria_for_status(status))
    
    
            if where:
                if properties is None:
                    properties = where
                else:
                    properties = {**where, **properties}
    
    
            if properties is not None:
    
                sub_criteria.extend(
                    list(
                        map(
                            lambda prop: _subcriteria_for_properties(
                                prop, properties[prop], entity="dataset"
                            ),
                            properties,
                        )
                    )
                )
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            search_criteria = get_search_type_for_entity("dataset")
            search_criteria["criteria"] = sub_criteria
            search_criteria["operator"] = "AND"
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            fetchopts = get_fetchoptions("dataSet", including=["type"])
            fetchopts["from"] = start_with
            fetchopts["count"] = count
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                "tags",
                "properties",
                "dataStore",
                "physicalData",
                "linkedData",
                "experiment",
                "sample",
                "registrator",
                "modifier",
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            fetchopts["experiment"]["project"] = fetch_option["project"]
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                if kind not in ["PHYSICAL_DATA", "CONTAINER", "LINK"]:
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    raise ValueError(
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                        "unknown dataSet kind: {}. It should be one of the following: PHYSICAL_DATA, CONTAINER or LINK".format(
                            kind
                        )
                    )
                fetchopts["kind"] = kind
                raise NotImplementedError("you cannot search for dataSet kinds yet")
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                "params": [
                    self.token,
                    search_criteria,
                    fetchopts,
                ],
    
            }
            resp = self._post_request(self.as_v3, request)
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            for obj in resp["objects"]:
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    openbis_obj=self,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    type=self.get_dataset_type(obj["type"]["code"]),
                    data=obj,
    
                datasets.append(dataset)
    
            return self._dataset_list_for_response(
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                response=resp["objects"],
    
                attrs=attrs,
                props=props,
                start_with=start_with,
                count=count,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                totalCount=resp["totalCount"],
    
        def get_experiment(
            self, code, withAttachments=False, only_data=False, use_cache=True
        ):
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            """Returns an experiment object for a given identifier (code)."""
    
            experiment = (
                not only_data
                and use_cache
                and self._object_cache(entity="experiment", code=code)
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            fetchopts = fetch_option["experiment"]
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            search_request = _type_for_id(code, "experiment")
            for option in [
                "tags",
                "properties",
                "attachments",
                "project",
                "samples",
                "registrator",
                "modifier",
            ]:
    
                fetchopts[option] = fetch_option[option]
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                fetchopts["attachments"] = fetch_option["attachmentsWithContent"]
    
            request = {
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                "params": [self.token, [search_request], fetchopts],
    
            resp = self._post_request(self.as_v3, request)
            if len(resp) == 0:
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                raise ValueError(f"No such experiment: {code}")
    
            data = resp[code]
            if only_data:
                return data
    
            experiment = Experiment(
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                openbis_obj=self,
                type=self.get_experiment_type(data["type"]["code"]),
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                data=data,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                identifier = data["identifier"]["identifier"]
                self._object_cache(entity="experiment", code=identifier, value=experiment)
    
        get_collection = get_experiment  # Alias
    
    
    Swen Vermeul's avatar
    Swen Vermeul committed
        def new_experiment(self, type, code, project, props=None, **kwargs):
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            """Creates a new experiment of a given experiment type."""
    
            return Experiment(
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                openbis_obj=self,
                type=self.get_experiment_type(type),
                project=project,
                data=None,
                props=props,
                code=code,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                **kwargs,
    
        new_collection = new_experiment  # Alias
    
    
    Swen Vermeul's avatar
    Swen Vermeul committed
        def create_external_data_management_system(
            self, code, label, address, address_type="FILE_SYSTEM"
        ):
    
            """Create an external DMS.
            :param code: An openBIS code for the external DMS.
            :param label: A human-readable label.
            :param address: The address for accessing the external DMS. E.g., a URL.
    
            :param address_type: One of OPENBIS, URL, or FILE_SYSTEM
    
            :return:
            """
            request = {
                "method": "createExternalDataManagementSystems",
                "params": [
                    self.token,
                    [
                        {
                            "code": code,
                            "label": label,
                            "addressType": address_type,
                            "address": address,
                            "@type": "as.dto.externaldms.create.ExternalDmsCreation",
                        }
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    ],
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            return self.get_external_data_management_system(resp[0]["permId"])
    
        def delete_entity(self, entity, id, reason, id_name="permId"):
            """Deletes Spaces, Projects, Experiments, Samples and DataSets"""
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            type = get_type_for_entity(entity, "delete")
            method = get_method_for_entity(entity, "delete")
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                "method": method,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    [{id_name: id, "@type": type}],
                    {"reason": reason, "@type": type},
                ],
    
            self._post_request(self.as_v3, request)
    
    Swen Vermeul's avatar
    Swen Vermeul committed
        def delete_openbis_entity(self, entity, objectId, reason="No reason given"):
            method = get_method_for_entity(entity, "delete")
            delete_options = get_type_for_entity(entity, "delete")
            delete_options["reason"] = reason
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            request = {"method": method, "params": [self.token, [objectId], delete_options]}
    
            self._post_request(self.as_v3, request)
    
    Swen Vermeul's avatar
    Swen Vermeul committed
        def get_deletions(self, start_with=None, count=None):
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            search_criteria = {"@type": "as.dto.deletion.search.DeletionSearchCriteria"}
            fetchopts = fetch_option["deletion"]
            fetchoptsDeleted = fetch_option["deletedObjects"]
            fetchoptsDeleted["from"] = start_with
            fetchoptsDeleted["count"] = count
            fetchopts["deletedObjects"] = fetchoptsDeleted
    
            request = {
                "method": "searchDeletions",
                "params": [
                    self.token,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    search_criteria,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    fetchopts,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                ],
    
            }
            resp = self._post_request(self.as_v3, request)
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            objects = resp["objects"]
    
            for value in objects:
                del_objs = extract_deletion(value)
                if len(del_objs) > 0:
                    new_objs.append(*del_objs)
    
            return DataFrame(new_objs)
    
        def new_project(self, space, code, description=None, **kwargs):
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            return Project(
                self, None, space=space, code=code, description=description, **kwargs
            )
    
    Swen Vermeul's avatar
    Swen Vermeul committed
        def _gen_fetchoptions(self, options, foType):
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            fo = {"@type": foType}
    
            for option in options:
                fo[option] = fetch_option[option]
            return fo
    
    
        def get_project(self, projectId, only_data=False, use_cache=True):
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            """Returns a Project object for a given identifier, code or permId."""
    
            project = (
                not only_data
                and use_cache
                and self._object_cache(entity="project", code=projectId)
            )
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            options = ["space", "registrator", "modifier", "attachments"]
    
            if is_identifier(projectId) or is_permid(projectId):
    
                request = self._create_get_request(
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    "getProjects",
                    "project",
                    projectId,
                    options,
                    "as.dto.project.fetchoptions.ProjectFetchOptions",
    
                )
                resp = self._post_request(self.as_v3, request)
    
                if only_data:
                    return resp[projectId]
    
    
                project = Project(openbis_obj=self, type=None, data=resp[projectId])
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    self._object_cache(entity="project", code=projectId, value=project)
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                search_criteria = _gen_search_criteria(
                    {"project": "Project", "operator": "AND", "code": projectId}
                )
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                fo = self._gen_fetchoptions(
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    options, foType="as.dto.project.fetchoptions.ProjectFetchOptions"
                )
    
                request = {
                    "method": "searchProjects",
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    "params": [self.token, search_criteria, fo],
    
                }
                resp = self._post_request(self.as_v3, request)
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                if len(resp["objects"]) == 0:
    
                    raise ValueError("No such project: %s" % projectId)
    
                if only_data:
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    return resp["objects"][0]
    
                project = Project(openbis_obj=self, type=None, data=resp["objects"][0])
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    self._object_cache(entity="project", code=projectId, value=project)
    
    Swen Vermeul's avatar
    Swen Vermeul committed
        def get_projects(
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            self,
            space=None,
            code=None,
            start_with=None,
            count=None,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
        ):
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            """Get a list of all available projects (DataFrame object)."""
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                sub_criteria.append(_subcriteria_for_code(space, "space"))
    
            if code:
                sub_criteria.append(_criteria_for_code(code))
    
    
            criteria = {
                "criteria": sub_criteria,
                "@type": "as.dto.project.search.ProjectSearchCriteria",
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                "operator": "AND",
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            fetchopts = {"@type": "as.dto.project.fetchoptions.ProjectFetchOptions"}
            fetchopts["from"] = start_with
            fetchopts["count"] = count
            for option in ["registrator", "modifier", "leader"]:
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                fetchopts[option] = fetch_option[option]
    
    
            request = {
                "method": "searchProjects",
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                "params": [
                    self.token,
                    criteria,
                    fetchopts,
                ],
    
            }
            resp = self._post_request(self.as_v3, request)
    
    
            def create_data_frame(attrs, props, response):
                attrs = [
                    "identifier",
                    "permId",
                    "leader",
                    "registrator",
                    "registrationDate",
                    "modifier",
                    "modificationDate",
                ]
                objects = response["objects"]
                if len(objects) == 0:
                    projects = DataFrame(columns=attrs)
                else:
                    parse_jackson(objects)
    
                    projects["registrationDate"] = projects["registrationDate"].map(
                        format_timestamp
                    )
                    projects["modificationDate"] = projects["modificationDate"].map(
                        format_timestamp
                    )
                    projects["leader"] = projects["leader"].map(extract_person)
                    projects["registrator"] = projects["registrator"].map(extract_person)
                    projects["modifier"] = projects["modifier"].map(extract_person)
                    projects["permId"] = projects["permId"].map(extract_permid)
                    projects["identifier"] = projects["identifier"].map(extract_identifier)
                return projects[attrs]
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                openbis_obj=self,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                entity="project",
                identifier_name="identifier",
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                start_with=start_with,
                count=count,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                totalCount=resp.get("totalCount"),
    
                df_initializer=create_data_frame,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
        def _create_get_request(self, method_name, entity, permids, options, foType):
    
    
            if not isinstance(permids, list):
                permids = [permids]
    
    
            type = "as.dto.{}.id.{}".format(entity.lower(), entity.capitalize())
    
            search_params = []
            for permid in permids:
                # decide if we got a permId or an identifier
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                match = re.match("/", permid)
    
                if match:
                    search_params.append(
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                        {"identifier": permid, "@type": type + "Identifier"}
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                    search_params.append({"permId": permid, "@type": type + "PermId"})
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            fo = {"@type": foType}
    
            for option in options:
                fo[option] = fetch_option[option]
    
            request = {
                "method": method_name,
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                "params": [self.token, search_params, fo],
    
            }
            return request
    
    
        def clear_cache(self, entity=None):
            """Empty the internal object cache
            If you do not specify any entity, the complete cache is cleared.
            As entity, you can specify either:
            space, project, vocabulary, term, sampleType, experimentType, dataSetType
            """
            if entity:
                self.cache[entity] = {}
            else:
                self.cache = {}
    
        def _object_cache(self, entity=None, code=None, value=None):
    
            # return the value, if no value provided
            if value is None:
                if entity in self.cache:
                    return self.cache[entity].get(code)
            else:
                if entity not in self.cache:
                    self.cache[entity] = {}
    
                self.cache[entity][code] = value
    
    
        def get_terms(self, vocabulary=None, start_with=None, count=None, use_cache=True):
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            """Returns information about existing vocabulary terms.
    
            If a vocabulary code is provided, it only returns the terms of that vocabulary.
    
    Swen Vermeul's avatar
    Swen Vermeul committed
            if (
    
                use_cache
                and self.use_cache
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                and vocabulary is not None
                and start_with is None
                and count is None
            ):
                voc = self._object_cache(entity="term", code=vocabulary)
    
            search_request = {}
            if vocabulary is not None:
    
    Swen Vermeul's avatar
    Swen Vermeul committed
                search_request = _gen_search_criteria(
                    {
                        "vocabulary": "VocabularyTerm",
                        "criteria": [{"vocabulary": "Vocabulary", "code": vocabulary}],
                    }
                )
            search_request[
                "@type"
            ] = "as.dto.vocabulary.search.VocabularyTermSearchCriteria"
    
            fetchopts = fetch_option["vocabularyTerm"]