"git@sissource.ethz.ch:sispub/openbis.git" did not exist on "884d0e37f4f5d49999a63b54d3517c6dc9c2521d"
Newer
Older
Adam Laskowski
committed
# Copyright ETH 2018 - 2023 Zürich, 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.
#
import json
Swen Vermeul
committed
import os
import random
import time
import urllib.parse
import uuid
import zipfile
from functools import partialmethod
from pathlib import Path
Swen Vermeul
committed
from queue import Queue
from threading import Thread
from urllib.parse import urljoin, quote
import requests
from pandas import DataFrame
from requests import Session
Swen Vermeul
committed
from tabulate import tabulate
from .definitions import (
openbis_definitions,
get_type_for_entity,
get_fetchoption_for_entity,
)
from .fast_download import FastDownload
from .openbis_object import OpenBisObject
from .things import Things
from .utils import (
VERBOSE,
parse_jackson,
extract_permid,
extract_code,
extract_downloadUrl,
)
# needed for Data upload
Swen Vermeul
committed
PYBIS_PLUGIN = "dataset-uploader-api"
dataset_definitions = openbis_definitions("dataSet")
dss_endpoint = "/datastore_server/rmi-data-store-server-v3.json"
Swen Vermeul
committed
def signed_to_unsigned(sig_int):
"""openBIS delivers crc32 checksums as signed integers.
If the number is negative, we just have to add 2**32
We display the hex number to match with the classic UI
"""
if sig_int < 0:
sig_int += 2 ** 32
return "%x" % (sig_int & 0xFFFFFFFF)
entity="dataSet",
single_item_method_name="get_dataset",
"""DataSet are openBIS objects that contain the actual files."""
def __init__(
self,
openbis_obj,
type,
data=None,
files=None,
zipfile=None,
folder=None,
kind=None,
props=None,
**kwargs,
if kind == "PHYSICAL":
if files is None and zipfile is None:
raise ValueError("please provide at least one file")
if files and zipfile:
raise ValueError(
"please provide either a list of files or a single zipfile"
)
if zipfile:
files = [zipfile]
if files:
if isinstance(files, str):
files = [files]
for file in files:
if not os.path.exists(file):
raise ValueError(f"File {file} does not exist")
# initialize the OpenBisObject
super().__init__(openbis_obj, type=type, data=data, props=props, **kwargs)
Swen Vermeul
committed
Swen Vermeul
committed
# existing DataSet
if data is not None:
if data["physicalData"] is None:
self.__dict__["shareId"] = None
self.__dict__["location"] = None
Swen Vermeul
committed
else:
self.__dict__["shareId"] = data["physicalData"]["shareId"]
self.__dict__["location"] = data["physicalData"]["location"]
if kind is not None:
kind = kind.upper()
allowed_kinds = ["PHYSICAL", "CONTAINER", "LINK"]
if kind not in allowed_kinds:
raise ValueError(
f"only these values are allowed for kind: {allowed_kinds}"
Swen Vermeul
committed
Swen Vermeul
committed
if getattr(self, "parents") is None:
self.a.__dict__["_parents"] = []
Swen Vermeul
committed
else:
if not self.is_new:
self.a.__dict__["_parents_orig"] = self.a.__dict__["_parents"]
Swen Vermeul
committed
if getattr(self, "children") is None:
self.a.__dict__["_children"] = []
Swen Vermeul
committed
else:
if not self.is_new:
self.a.__dict__["_children_orig"] = self.a.__dict__["_children"]
Swen Vermeul
committed
if getattr(self, "container") is None:
self.a.__dict__["_container"] = []
else:
if not self.is_new:
self.a.__dict__["_container_orig"] = self.a.__dict__["_container"]
if getattr(self, "component") is None:
self.a.__dict__["_component"] = []
else:
if not self.is_new:
self.a.__dict__["_component_orig"] = self.a.__dict__["_component"]
Swen Vermeul
committed
def __str__(self):
Swen Vermeul
committed
def __dir__(self):
return [
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
"get_parents()",
"get_children()",
"get_components()",
"get_contained()",
"get_containers()",
"add_parents()",
"add_children()",
"add_components()",
"add_contained()",
"add_containers()",
"del_parents()",
"del_children()",
"del_components()",
"del_contained()",
"del_containers()",
"set_parents()",
"set_children()",
"set_components()",
"set_contained()",
"set_containers()",
"set_tags()",
"add_tags()",
"del_tags()",
"add_attachment()",
"get_attachments()",
"download_attachments()",
"get_files()",
"file_list",
"file_links",
"rel_file_links",
"physicalData",
"download()",
"download_path",
"is_physical()",
"symlink()",
"is_symlink()",
"archive()",
"unarchive()",
"save()",
"delete()",
"mark_to_be_deleted()",
"unmark_to_be_deleted()",
"is_marked_to_be_deleted()",
"attrs",
"props",
Swen Vermeul
committed
def __setattr__(self, name, value):
Swen Vermeul
committed
self.__dict__[name] = value
if isinstance(value, dict):
for p in value:
else:
raise ValueError("please provide a dictionary for setting properties")
Swen Vermeul
committed
else:
super(DataSet, self).__setattr__(name, value)
@property
def props(self):
Swen Vermeul
committed
@property
def type(self):
Swen Vermeul
committed
@type.setter
def type(self, type_name):
dataset_type = self.openbis.get_dataset_type(type_name.upper())
self.p.__dict__["_type"] = dataset_type
self.a.__dict__["_type"] = dataset_type
Swen Vermeul
committed
@property
def physicalData(self):
if "physicalData" in self.data:
return PhysicalData(data=self.data["physicalData"])
Swen Vermeul
committed
@property
def linkedData(self):
if "linkedData" in self.data:
return LinkedData(data=self.data["linkedData"])
Swen Vermeul
committed
@property
def status(self):
ds = self.openbis.get_dataset(self.permId)
self.data["physicalData"] = ds.data["physicalData"]
Swen Vermeul
committed
try:
Swen Vermeul
committed
except Exception:
return None
vkovtun
committed
@property
def download_path(self):
"""after ther physical datasets have been downloaded, this returns the relative path."""
return self.__dict__.get("download_path", "")
def _sftp_source_dir(self):
"""The SFTP directory is structured as follows:
/SPACE/PROJECT/EXPERIMENT/permId
For the current dataSet, this method returns the expected path
return os.path.join(self.experiment.identifier[1:], self.permId)
def symlink(self, target_dir: str = None, replace_if_symlink_exists: bool = True):
"""replace_if_symlink_exists will replace the the target_dir
in case it is an existing symlink
Returns the absolute path of the symlink
if target_dir is None:
target_dir = os.path.join(self.openbis.download_prefix, self.permId)
target_dir_path = Path(target_dir)
if target_dir_path.is_symlink() and replace_if_symlink_exists:
target_dir_path.unlink()
# create data/openbis-hostname
os.makedirs(os.path.dirname(target_dir_path.absolute()), exist_ok=True)
# make sure we got a mountpoint
mountpoint_path = self.openbis.get_mountpoint()
if mountpoint_path is None:
try:
mountpoint_path = self.openbis.mount()
except ValueError as err:
if "password" in str(err):
raise ValueError(
"openBIS instance cannot be mounted, no symlink possible"
)
# construct the absolute path of our sftp source
sftp_source_path = os.path.join(mountpoint_path, self._sftp_source_dir)
# make sure our sftp source is really available
# create symlink
if os.path.exists(sftp_source_path):
target_dir_path.symlink_to(sftp_source_path, target_is_directory=True)
if VERBOSE:
print(f"Symlink created: {target_dir} --> {sftp_source_path}")
return str(target_dir_path.absolute())
else:
raise ValueError(
f"Source path {sftp_source_path} does not exist, cannot create symlink"
)
@staticmethod
def _file_set(target_dir: str) -> Set[str]:
target_dir_path = Path(target_dir)
return set(
str(el.relative_to(target_dir_path))
for el in target_dir_path.glob("**/*")
if el.is_file()
)
def _is_symlink_or_physical(
self,
what: str,
target_dir: str = None,
expected_file_list: Optional[List[str]] = None,
if target_dir is None:
target_dir = os.path.join(self.openbis.download_prefix, self.permId)
target_dir_path = Path(target_dir)
target_file_set = self._file_set(target_dir)
if expected_file_list is None:
source_file_set = set(self.file_list)
else:
source_file_set = set(expected_file_list)
res = source_file_set.issubset(target_file_set)
if not res:
return res
elif what == "symlink":
return target_dir_path.exists() and target_dir_path.is_symlink()
elif what == "physical":
return target_dir_path.exists() and not target_dir_path.is_symlink()
else:
raise ValueError("Unexpected error")
is_symlink = partialmethod(
_is_symlink_or_physical, what="symlink", expected_file_list=None
)
is_physical = partialmethod(_is_symlink_or_physical, what="physical")
Swen Vermeul
committed
def archive(self, remove_from_data_store=True):
fetchopts = {
"removeFromDataStore": remove_from_data_store,
"@type": "as.dto.dataset.archive.DataSetArchiveOptions",
Swen Vermeul
committed
}
self.archive_unarchive("archiveDataSets", fetchopts)
if VERBOSE:
print(f"DataSet {self.permId} archived")
Swen Vermeul
committed
def unarchive(self):
fetchopts = {"@type": "as.dto.dataset.unarchive.DataSetUnarchiveOptions"}
self.archive_unarchive("unarchiveDataSets", fetchopts)
if VERBOSE:
print(f"DataSet {self.permId} unarchived")
Swen Vermeul
committed
def archive_unarchive(self, method, fetchopts):
payload = {}
request = {
"method": method,
"params": [
self.openbis.token,
[{"permId": self.permId, "@type": "as.dto.dataset.id.DataSetPermId"}],
dict(fetchopts),
Swen Vermeul
committed
],
}
resp = self.openbis._post_request(self._openbis.as_v3, request)
return
def set_properties(self, properties):
Swen Vermeul
committed
"""expects a dictionary of property names and their values.
Does not save the dataset.
"""
for prop in properties.keys():
setattr(self.p, prop, properties[prop])
set_props = set_properties
Swen Vermeul
committed
def get_dataset_files(self, start_with=None, count=None, **properties):
search_criteria = get_type_for_entity("dataSetFile", "search")
search_criteria["operator"] = "AND"
search_criteria["criteria"] = [
{
"criteria": [
{
"fieldName": "code",
"fieldType": "ATTRIBUTE",
"fieldValue": {
"value": self.permId,
"@type": "as.dto.common.search.StringEqualToValue",
},
"@type": "as.dto.common.search.CodeSearchCriteria",
}
],
"operator": "OR",
"@type": "as.dto.dataset.search.DataSetSearchCriteria",
}
]
fetchopts = get_fetchoption_for_entity("dataSetFile")
request = {
"method": "searchFiles",
"params": [
self.openbis.token,
search_criteria,
fetchopts,
],
}
full_url = urljoin(self._get_download_url(), dss_endpoint)
resp = self.openbis._post_request_full_url(full_url, request)
vkovtun
committed
def create_data_frame(attrs, props, response):
vkovtun
committed
parse_jackson(objects)
attrs = [
"dataSetPermId",
"dataStore",
"downloadUrl",
"path",
"directory",
"fileLength",
"checksumCRC32",
"checksum",
"checksumType",
vkovtun
committed
]
dataSetFiles = None
if len(objects) == 0:
dataSetFiles = DataFrame(columns=attrs)
else:
dataSetFiles = DataFrame(objects)
dataSetFiles["downloadUrl"] = dataSetFiles["dataStore"].map(
extract_downloadUrl
)
dataSetFiles["checksumCRC32"] = (
dataSetFiles["checksumCRC32"]
.fillna(0.0)
.astype(int)
.map(signed_to_unsigned)
)
dataSetFiles["dataStore"] = dataSetFiles["dataStore"].map(extract_code)
dataSetFiles["dataSetPermId"] = dataSetFiles["dataSetPermId"].map(
extract_permid
)
vkovtun
committed
return dataSetFiles[attrs]
return Things(
openbis_obj=self.openbis,
entity="dataSetFile",
identifier_name="dataSetPermId",
start_with=start_with,
count=count,
vkovtun
committed
response=resp,
self,
files=None,
destination=None,
create_default_folders=True,
wait_until_finished=True,
workers=10,
linked_dataset_fileservice_url=None,
Adam Laskowski
committed
content_copy_index=0
files -- a single file or a list of files. If no files are specified, all files of a given dataset are downloaded.
destination -- if destination is specified, files are downloaded in __current_dir__/destination/permId/ If no destination is specified, the hostname is chosen instead of destination
create_default_folders -- by default, this download method will automatically create destination/permId/original/DEFAULT. If create_default_folders is set to False, all these folders will be ommited. Use with care and by specifying the destination folder.
workers -- Default: 10. Files are usually downloaded in parallel, using 10 workers by default.
wait_unitl_finished -- True. If you want to immediately continue and run the download in background, set this to False.
Swen Vermeul
committed
"""
if files == None:
files = self.file_list
elif isinstance(files, str):
files = [files]
if destination is None:
destination = self.openbis.download_prefix
# destination = self.openbis.hostname
kind = None
if "kind" in self.data: # openBIS 18.6.x DTO
kind = self.data["kind"]
elif ("type" in self.data) and (
"kind" in self.data["type"]
): # openBIS 16.5.x DTO
kind = self.data["type"]["kind"]
if kind in ["PHYSICAL", "CONTAINER"]:
Adam Laskowski
committed
if self.openbis.get_server_information().is_version_greater_than(3, 5):
return self._download_fast_physical(files, destination, create_default_folders,
wait_until_finished)
else:
return self._download_physical(
files, destination, create_default_folders, wait_until_finished, workers
)

yvesn
committed
if linked_dataset_fileservice_url is None:
raise ValueError(
"Can't download a LINK data set without the linked_dataset_fileservice_url parameters."
)
return self._download_link(
files,
destination,
wait_until_finished,
workers,
linked_dataset_fileservice_url,
content_copy_index,
)

yvesn
committed
else:
raise ValueError(f"Can't download data set of kind {kind}.")

yvesn
committed
def _download_fast_physical(
self, files, destination, create_default_folders, wait_until_finished
):
"""Download for data sets of kind PHYSICAL using fast download scheme"""
if create_default_folders:
final_destination = os.path.join(destination, self.permId)
else:
final_destination = destination
self.__dict__["download_path"] = final_destination
download_url = self._get_download_url()
fast_download = FastDownload(self.openbis.token, download_url, self.permId, files,
final_destination, create_default_folders, wait_until_finished,
self.openbis.verify_certificates,
wished_number_of_streams=4)
return fast_download.download()
self, files, destination, create_default_folders, wait_until_finished, workers
):
"""Download for data sets of kind PHYSICAL."""

yvesn
committed
final_destination = ""
if create_default_folders:
final_destination = os.path.join(destination, self.permId)
else:
final_destination = destination
vkovtun
committed
self.__dict__["download_path"] = final_destination
download_url = self._get_download_url()
base_url = download_url + "/datastore_server/" + self.permId + "/"
Swen Vermeul
committed
with DataSetDownloadQueue(workers=workers) as queue:
# get file list and start download
for filename in files:
fi_df = self.get_dataset_files().df
file_size = fi_df[fi_df["path"] == filename]["fileLength"].values[0]
download_url = base_url + filename + "?sessionID=" + self.openbis.token
download_url = quote(download_url, safe=":/?=")
filename_dest = ""
if create_default_folders:
# create original/ or original/DEFAULT subfolders
filename_dest = os.path.join(final_destination, filename)
else:
# ignore original/ and original/DEFAULT folders that come from openBIS
if filename.startswith("original/"):
filename = filename.replace("original/", "", 1)
if filename.startswith("DEFAULT/"):
filename = filename.replace("DEFAULT/", "", 1)
filename_dest = os.path.join(final_destination, filename)
queue.put(
[
download_url,
filename,
filename_dest,
file_size,
self.openbis.verify_certificates,
"wb",
]
)
Swen Vermeul
committed
Swen Vermeul
committed
# wait until all files have downloaded
if wait_until_finished:
queue.join()
Swen Vermeul
committed
print(f"Files downloaded to: {os.path.join(final_destination)}")
return final_destination
Swen Vermeul
committed
self,
files,
destination,
wait_until_finished,
workers,
linked_dataset_fileservice_url,
content_copy_index,

yvesn
committed
Requires the microservice server to be running at the given linked_dataset_fileservice_url.
"""
workers=workers, collect_files_with_wrong_length=True

yvesn
committed
Swen Vermeul
committed
if content_copy_index >= len(self.data["linkedData"]["contentCopies"]):
raise ValueError("Content Copy index out of range.")
content_copy = self.data["linkedData"]["contentCopies"][content_copy_index]

yvesn
committed
Swen Vermeul
committed
for filename in files:
fi_df = self.get_dataset_files().df
file_size = fi_df[fi_df["path"] == filename]["fileLength"].values[0]

yvesn
committed
Swen Vermeul
committed
download_url = linked_dataset_fileservice_url
download_url += "?sessionToken=" + self.openbis.token
download_url += "&datasetPermId=" + self.data["permId"]["permId"]
"&externalDMSCode=" + content_copy["externalDms"]["code"]
)
download_url += "&contentCopyPath=" + content_copy["path"].replace(
"/", "%2F"
)
Swen Vermeul
committed
download_url += "&datasetPathToFile=" + urllib.parse.quote(filename)

yvesn
committed
Swen Vermeul
committed
filename_dest = os.path.join(destination, self.permId, filename)

yvesn
committed
Swen Vermeul
committed
# continue download if file is not complete - do nothing if it is
Swen Vermeul
committed
if os.path.exists(filename_dest):
actual_size = os.path.getsize(filename_dest)
if actual_size == int(file_size):
continue
elif actual_size < int(file_size):
Swen Vermeul
committed
download_url += "&offset=" + str(actual_size)

yvesn
committed
queue.put(
[
download_url,
filename,
filename_dest,
file_size,
self.openbis.verify_certificates,
write_mode,
]
)

yvesn
committed
Swen Vermeul
committed
if wait_until_finished:
queue.join()

yvesn
committed
if VERBOSE:
print(
"Files downloaded to: %s" % os.path.join(destination, self.permId)
)
Swen Vermeul
committed
return destination, queue.files_with_wrong_length

yvesn
committed
Swen Vermeul
committed
@property
def folder(self):
Swen Vermeul
committed
@property
def file_list(self):
"""Returns the list of files including their directories as an array of strings.
Folders are not listed.
Swen Vermeul
committed
"""
if self.is_new:
return self.files
else:
fl = self.get_dataset_files().df
return fl[fl["directory"] == False]["path"].to_list()
vkovtun
committed
"""Returns a dictionary of absolute file links for every file in this dataSet.
As the link also contains a session token (sessionID), sharing this link might be
a security risk. When the token is no longer valid, the link will no longer work either.
"""
location_part = self.physicalData.location.split("/")[-1]
token = self.openbis.token
file_links = {}
for filepath in self.file_list:
quoted_filepath = urllib.parse.quote(filepath, safe="")
file_links[filepath] = (
"/".join([url, "datastore_server", location_part, quoted_filepath])
+ "?sessionID="
+ token
vkovtun
committed
Swen Vermeul
committed
@property
def rel_file_links(self):
"""Returns a dictionary of relative file links for every file in this dataSet. These relative file link can be embedded in a <img src="{rel_link}">
element within a XML property. If the dataSet file happens to be a picture, in ELN-LIMS, the picture will be displayed inline.
"""
if self.is_new:
location_part = self.physicalData.location.split("/")[-1]
vkovtun
committed
rel_file_links = {}
for filepath in self.file_list:
quoted_filepath = urllib.parse.quote(filepath, safe="")
rel_file_links[filepath] = "/".join(
["/datastore_server", location_part, quoted_filepath]
)
vkovtun
committed
def get_files(self, start_folder="/"):
"""Returns a DataFrame of all files in this dataset"""
if start_folder.startswith("/"):
start_folder = start_folder[1:]
file_list = self.get_dataset_files().df
file_list[file_list["path"].str.startswith(start_folder)]
new_file_list = file_list[
["directory", "path", "fileLength", "checksumCRC32"]
].rename(
columns={
"directory": "isDirectory",
"path": "pathInDataSet",
"fileLength": "fileSize",
"checksumCRC32": "crc32Checksum",
}
return new_file_list
Swen Vermeul
committed
def _get_download_url(self):
download_url = ""
if "downloadUrl" in self.data["dataStore"]:
vkovtun
committed
download_url = self.data["dataStore"]["downloadUrl"]
else:
# fallback, if there is no dataStore defined
datastores = self.openbis.get_datastores()
return download_url
Swen Vermeul
committed
def get_file_list(self, recursive=True, start_folder="/"):
"""Lists all files of a given dataset. You can specifiy a start_folder other than "/".
By default, all directories and their containing files are listed recursively. You can
turn off this option by setting recursive=False.
"""
print("This method is deprecated. Consider using get_files() instead")
Swen Vermeul
committed
request = {
"method": "listFilesForDataSet",
"params": [
self.openbis.token,
self.permId,
start_folder,
recursive,
],
Swen Vermeul
committed
}
download_url = self._get_download_url()
Swen Vermeul
committed
resp = requests.post(
download_url + "/datastore_server/rmi-dss-api-v1.json",
Swen Vermeul
committed
json.dumps(request),
Swen Vermeul
committed
)
if resp.ok:
data = resp.json()
if "error" in data:
raise ValueError("Error from openBIS: " + data["error"]["message"])
elif "result" in data:
return data["result"]
Swen Vermeul
committed
else:
raise ValueError(
"request to openBIS did not return either result nor error"
)
Swen Vermeul
committed
else:
raise ValueError("internal error while performing post request")
Swen Vermeul
committed
def _generate_plugin_request(self, dss, permId=None):
Swen Vermeul
committed
"""generates a request to activate the dataset-uploader ingestion plugin to
register our files as a new dataset
"""
sample_identifier = None
if self.sample is not None:
sample_identifier = self.sample.identifier
experiment_identifier = None
if self.experiment is not None:
experiment_identifier = self.experiment.identifier
parentIds = self.parents
if parentIds is None:
parentIds = []
Swen Vermeul
committed
dataset_type = self.type.code
properties = self.props.all_nonempty()
request = {
"method": "createReportFromAggregationService",
"params": [
self.openbis.token,
dss,
PYBIS_PLUGIN,
{
"permId": permId,
"method": "insertDataSet",
"sampleIdentifier": sample_identifier,
"experimentIdentifier": experiment_identifier,
"dataSetType": dataset_type,
"folderName": self.folder,
"fileNames": self.files_in_wsp,
"isZipDirectoryUpload": self.isZipDirectoryUpload,
"properties": properties,
"parentIdentifiers": parentIds,
},
Swen Vermeul
committed
],
}
return request
for prop_name, prop in self.props._property_names.items():
getattr(self.props, prop_name) is None
or getattr(self.props, prop_name) == ""
f"Property '{prop_name}' is mandatory and must not be None"
Swen Vermeul
committed
if self.is_new:
data_stores = self.openbis.get_datastores()
vkovtun
committed
Swen Vermeul
committed
if self.sample is None and self.experiment is None:
raise ValueError(
"A DataSet must be either connected to a Sample or an Experiment"
)
Swen Vermeul
committed
if self.kind == "PHYSICAL":
if self.files is None or len(self.files) == 0:
raise ValueError(
"Cannot register a dataset without a file. Please provide at least one file"
if self.openbis.get_server_information().is_version_greater_than(3, 5):
return self._upload_v3(data_stores)
vkovtun
committed
return self._upload_v1(permId, data_stores)
vkovtun
committed
# CONTAINER
Swen Vermeul
committed
else:
if self.files is not None and len(self.files) > 0:
raise ValueError(
"DataSets of kind CONTAINER or LINK cannot contain data"
vkovtun
committed
request = self._new_attrs()
# if no code for the container was provided, let openBIS
# generate the code automatically
if self.code is None or self.code == "":
request["params"][1][0]["autoGeneratedCode"] = True
else:
request["params"][1][0]["autoGeneratedCode"] = False
DSpermId = data_stores["code"][0]
request["params"][1][0]["properties"] = props
request["params"][1][0]["dataStoreId"] = {
"permId": DSpermId,
"@type": "as.dto.datastore.id.DataStorePermId",
}
resp = self.openbis._post_request(self.openbis.as_v3, request)
if VERBOSE:
print("DataSet successfully created.")
new_dataset_data = self.openbis.get_dataset(
resp[0]["permId"], only_data=True
)
self._set_data(new_dataset_data)
return self
Swen Vermeul
committed
# updating the DataSET
Swen Vermeul
committed
else:
request = self._up_attrs()
props = self.p._all_props()
request["params"][1][0]["properties"] = props
self.openbis._post_request(self.openbis.as_v3, request)
if VERBOSE:
print("DataSet successfully updated.")
Swen Vermeul
committed
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
def _upload_v1(self, permId, datastores):
# for uploading phyiscal data, we first upload it to the session workspace
self.upload_files_v1(
datastore_url=datastores["downloadUrl"][0],
files=self.files,
folder="",
wait_until_finished=True,
)
# activate the ingestion plugin, as soon as the data is uploaded
# this will actually register the dataset in the datastore and the AS
request = self._generate_plugin_request(
dss=datastores["code"][0],
permId=permId,
)
resp = self.openbis._post_request(self.openbis.reg_v1, request)
if resp["rows"][0][0]["value"] == "OK":
permId = resp["rows"][0][2]["value"]
if permId is None or permId == "":
self.__dict__["is_new"] = False
if VERBOSE:
print(
"DataSet successfully created. Because you connected to an openBIS version older than 16.05.04, you cannot update the object."
)
else:
new_dataset_data = self.openbis.get_dataset(
permId, only_data=True
)
self._set_data(new_dataset_data)
if VERBOSE:
print("DataSet successfully created.")
return self
else:
print(json.dumps(request))
raise ValueError(
"Error while creating the DataSet: "
+ resp["rows"][0][1]["value"]
)
def _upload_v3(self, data_stores):
upload_id = str(uuid.uuid4())
datastore_url = data_stores["downloadUrl"][0]
# for uploading phyiscal data, we first upload it to the session workspace
self.upload_files_v3(
upload_id=upload_id,
datastore_url=datastore_url,
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
files=self.files,
folder="",
wait_until_finished=True,
)
param = {
"@type": "dss.dto.dataset.create.UploadedDataSetCreation",
"@id": "1",
"typeId": {
"@type": "as.dto.entitytype.id.EntityTypePermId",
"@id": "2",
"permId": self.type.code,
"entityKind": "DATA_SET"},
"properties": self.props.all_nonempty(),
"parentIds": [],
"uploadId": upload_id
}
if self.experiment is not None:
param["experimentId"] = {
"@type": "as.dto.experiment.id.ExperimentIdentifier",
"@id": "3",
"identifier": self.experiment.identifier
}
if self.sample is not None:
param["sampleId"] = {
"@type": "as.dto.sample.id.SamplePermId",
"@id": "4",
"permId": self.sample.permId
}
# TODO: check if this part is needed
parent_ids = self.parents
if parent_ids is None:
parent_ids = []
counter = 5
for parent_id in parent_ids:
param["parentIds"] += {
"@type": "as.dto.dataset.id.DataSetPermId",
"@id": str(counter),
"permId": parent_id
}
counter += 1