diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 0000000..bea6287
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,39 @@
+# Python CircleCI 2.0 configuration file
+version: 2.1
+jobs:
+ cordrapy_develop:
+ docker:
+ - image: continuumio/miniconda3
+
+ working_directory: ~/repo-test-cordrapy
+
+ steps:
+ # Step 1: obtain repo from GitHub
+ - checkout
+ # Step 2: Get and run cordra
+ - run:
+ name: Get Cordra
+ command: |
+ ls
+ set -e
+ apt-get --yes update
+ apt-get --yes upgrade
+ apt-get --yes install curl unzip default-jre
+ curl https://www.cordra.org/assets/sw/cordra-2.4.0-distribution.zip > cordra-2.4.0-distribution.zip
+ unzip cordra-2.4.0-distribution.zip
+ cd cordra-2.4.0
+ rm data/repoInit.json
+ echo '{"adminPassword": "admin","prefix": ""}' > data/repoInit.json
+ (./bin/startup &) | grep -q "Startup complete."
+ cd ../
+ pip install -r requirements.txt
+ pip install Pillow
+ pip install -e ./
+ python tests/CRUD_CordraClient.py
+
+
+workflows:
+ version: 2
+ test:
+ jobs:
+ - cordrapy_develop
\ No newline at end of file
diff --git a/cordra/__init__.py b/cordra/__init__.py
index 5417a0b..7384af4 100644
--- a/cordra/__init__.py
+++ b/cordra/__init__.py
@@ -2,6 +2,8 @@
"""
from .cordra import CordraObject, Token
+from .cordraClient import CordraClient
+
def get_version():
"""Get the version of the code from egg_info.
@@ -22,6 +24,7 @@ def get_version():
__all__ = [
"__version__",
+ "Token",
"CordraObject",
- "Token"
+ "CordraClient"
]
\ No newline at end of file
diff --git a/cordra/cordra.py b/cordra/cordra.py
index e686280..e9dfd52 100644
--- a/cordra/cordra.py
+++ b/cordra/cordra.py
@@ -1,7 +1,8 @@
import requests
import json
+from warnings import warn
-from requests.packages.urllib3.exceptions import InsecureRequestWarning
+from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# global variables
@@ -13,6 +14,7 @@
token_grant_type = 'password'
token_type = 'Bearer'
+
def endpoint_url(host, endpoint):
return host.strip('/') + '/' + endpoint
@@ -29,7 +31,7 @@ def check_response(response):
try:
return response.json()
except BaseException:
- return response.text
+ return response.content
def set_auth(username, password):
@@ -39,6 +41,7 @@ def set_auth(username, password):
auth = None
return auth
+
def get_token_value(token):
if isinstance(token, str):
return token
@@ -59,7 +62,11 @@ def set_headers(token):
headers = None
return headers
+
class CordraObject:
+ warn("CordraObject may be moved to a new module with a new name in future releases.")
+
+ @staticmethod
def create(
host,
obj_json,
@@ -73,7 +80,8 @@ def create(
verify=None,
full=False,
payloads=None,
- acls=None
+ acls=None,
+ **kwargs
):
'''Create a Cordra object'''
@@ -135,6 +143,7 @@ def create(
else:
return obj_r
+ @staticmethod
def read(
host,
obj_id,
@@ -144,7 +153,8 @@ def read(
verify=None,
jsonPointer=None,
jsonFilter=None,
- full=False
+ full=False,
+ **kwargs
):
'''Retrieve a Cordra object JSON by identifer.'''
@@ -165,13 +175,15 @@ def read(
verify=verify))
return r
+ @staticmethod
def read_payload_info(
host,
obj_id,
username=None,
password=None,
token=None,
- verify=None
+ verify=None,
+ **kwargs
):
'''Retrieve a Cordra object payload names by identifer.'''
@@ -188,6 +200,7 @@ def read_payload_info(
verify=verify))
return r['payloads']
+ @staticmethod
def read_payload(
host,
obj_id,
@@ -195,7 +208,8 @@ def read_payload(
username=None,
password=None,
token=None,
- verify=None
+ verify=None,
+ **kwargs
):
'''Retrieve a Cordra object payload by identifer and payload name.'''
@@ -212,6 +226,7 @@ def read_payload(
verify=verify))
return r
+ @staticmethod
def update(
host,
obj_id,
@@ -226,7 +241,8 @@ def update(
full=False,
payloads=None,
payloadToDelete=None,
- acls=None
+ acls=None,
+ **kwargs
):
'''Update a Cordra object'''
@@ -289,6 +305,7 @@ def update(
return r
+ @staticmethod
def delete(
host,
obj_id,
@@ -296,7 +313,8 @@ def delete(
username=None,
password=None,
token=None,
- verify=None
+ verify=None,
+ **kwargs
):
'''Delete a Cordra object'''
@@ -316,6 +334,7 @@ def delete(
)
return r
+ @staticmethod
def find(
host,
query,
@@ -325,13 +344,19 @@ def find(
verify=None,
ids=False,
jsonFilter=None,
- full=False
+ full=False,
+ pageNum=None,
+ pageSize=None,
+ **kwargs
):
'''Find a Cordra object by query'''
params = dict()
params['query'] = query
params['full'] = full
+ if pageNum: params["pageNum"] = pageNum
+ if pageSize: params["pageSize"] = pageSize
+
if jsonFilter:
params['filter'] = str(jsonFilter)
if ids:
@@ -348,12 +373,16 @@ def find(
return r
class Token:
+ warn("Token may be moved to a new module with a new name in future releases.")
+
+ @staticmethod
def create(
host,
username,
password,
verify=None,
- full=False
+ full=False,
+ **kwargs
):
'''Create an access Token'''
@@ -373,11 +402,13 @@ def create(
verify=verify))
return r
+ @staticmethod
def read(
host,
token,
verify=None,
- full=False
+ full=False,
+ **kwargs
):
'''Read an access Token'''
@@ -396,10 +427,12 @@ def read(
))
return r
+ @staticmethod
def delete(
host,
token,
- verify=None
+ verify=None,
+ **kwargs
):
'''Delete an access Token'''
diff --git a/cordra/cordraClient.py b/cordra/cordraClient.py
new file mode 100644
index 0000000..46cb808
--- /dev/null
+++ b/cordra/cordraClient.py
@@ -0,0 +1,158 @@
+# Standard Library packages
+from typing import Dict
+import json
+import os
+from copy import deepcopy
+
+# Local imports
+from .cordra import CordraObject, Token, check_response
+
+
+class CordraClient:
+ """
+ Supports CRUD operations with a running Cordra instance allows access to the full
+ functionality of the Cordra REST API. This includes:
+ * Authorization using user / password
+ * Authorization using a secret key
+ * Provide a token for subsequent authorization
+ * Delete a token
+ * Create a cordra object
+ * Setting the ACL on a cordra object on create
+ * Updating a cordra object
+ * Updating a cordra object attribute
+ * Updating a cordra object payload
+ * Updating the ACL of a cordra object
+ * Deleting a cordra object
+ * Deleting a cordra object attribute
+ * Deleting a cordra object payload
+ * Querying cordra
+
+ Attributes:
+ host: the location of the cordra instance (URL).
+ credentials_file: the location of a user's credentials.
+ credentials_token: a credentials token file.
+ params: parameters that will be passed with each request.
+
+ >>> import cordra
+ >>> test_object = cordra.CordraClient("testhost")
+ >>> print(test_object)
+ Connection via CordraPy to testhost
+ """
+
+ host: str #URL
+ handle: str="prefix"
+ username: str
+ password: str
+ secret_key_path: str #FilePath
+ params: Dict
+
+
+ def __str__(self):
+ return f"Connection via CordraPy to {self.host}"
+
+
+ def __init__(self, **params):
+ assert "host" in params, "Host must be specified to use CordraClient"
+ assert ("username" in params and "password" in params) or "secret_key_path" in params, \
+ "Client requires `username` and `password` params or a `secret_key_path` param"
+ self.params = dict()
+ self.params.update(params)
+
+ if "username" in params:
+ self.get_auth()
+ del self.params["username"]
+ del self.params["password"]
+ elif "secret_key_path" in params:
+ raise NotImplementedError
+ else:
+ raise Exception
+
+ self.schemas = {
+ r.get("name"): r.get("schema")
+ for r in self.find("type:Schema")['results']
+ }
+
+
+ def get_auth(self):
+ """Get a token with credentials"""
+ r = Token.create(**self.params)
+
+ # Set up variables and default auth for future requests
+ self.params["token"] = r["access_token"]
+
+
+ def check_auth(self):
+ """Checks an access Token"""
+ r = Token.read(**self.params)
+ return r
+
+
+ def delete_auth(self):
+ """Delete an access Token"""
+ r = Token.delete(**self.params)
+ return r
+
+
+ def create(self, obj, obj_type, **kwargs):
+ """Creates an object"""
+
+ params = deepcopy(self.params)
+ params.update(kwargs)
+
+ return CordraObject.create(obj_json=obj, obj_type=obj_type, **params)
+
+
+ def read(self, obj_id, getObjPayTuple=False, **kwargs):
+ """Retrieve an object from Cordra by identifer and create a
+ python CordraObject."""
+
+ params = deepcopy(self.params)
+ params.update(kwargs)
+
+ if getObjPayTuple:
+ params["full"] = True
+
+ obj = CordraObject.read(obj_id=obj_id, **params)
+
+ if getObjPayTuple:
+ if "payloads" not in obj:
+ return (obj["content"], None)
+
+ payload_info = deepcopy( obj["payloads"] )
+ obj["payloads"] = dict()
+ payload_info = CordraObject.read_payload_info(obj_id=obj_id, **params)
+
+ for pay in payload_info:
+ payName = pay.get("name")
+ obj["payloads"][payName] = CordraObject.read_payload(obj_id=obj_id, payload=payName, **params)
+
+ return (obj["content"], obj["payloads"])
+
+ return obj
+
+
+ def update(self, obj, obj_id, **kwargs):
+ """Updates an object"""
+
+ params = deepcopy(self.params)
+ params.update(kwargs)
+
+ return CordraObject.update(obj_id=obj_id, obj_json=obj, **params)
+
+
+ def delete(self, obj_id, **kwargs):
+ """Delete a Cordra object or part of a Cordra Object"""
+
+ params = deepcopy(self.params)
+ params.update(kwargs)
+
+ return CordraObject.delete(obj_id=obj_id, **params)
+
+
+ def find(self, query, **kwargs):
+ """Find a Cordra object by query"""
+
+ params = deepcopy(self.params)
+ params.update(kwargs)
+
+ return CordraObject.find(query=query, **params)
diff --git a/examples/examples-Client.ipynb b/examples/examples-Client.ipynb
new file mode 100644
index 0000000..bc5f521
--- /dev/null
+++ b/examples/examples-Client.ipynb
@@ -0,0 +1,904 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/home/sven/7/Work/ThesisMatData/CordraPy/cordra/cordra.py:67: UserWarning: CordraObject may be moved to a new module with a new name in future releases.\n",
+ " warn(\"CordraObject may be moved to a new module with a new name in future releases.\")\n",
+ "/home/sven/7/Work/ThesisMatData/CordraPy/cordra/cordra.py:376: UserWarning: Token may be moved to a new module with a new name in future releases.\n",
+ " warn(\"Token may be moved to a new module with a new name in future releases.\")\n"
+ ]
+ }
+ ],
+ "source": [
+ "import getpass\n",
+ "import cordra\n",
+ "from lucenequerybuilder import Q\n",
+ "from io import StringIO\n",
+ "import pandas as pd\n",
+ "import matplotlib.pyplot as plt\n",
+ "from urllib.error import HTTPError"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Cordra Host Information"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "host = \"https://localhost:8443/\"\n",
+ "\n",
+ "localhost = cordra.CordraClient(host=host, username=\"admin\", password=\"admin\", verify=False)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "dict_keys(['User', 'Document', 'Group'])"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "localhost.schemas.keys()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "obj_type = \"Document\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Create two similar objects"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'id': 'test/f1f0188d7e74ce2e9b39',\n",
+ " 'name': 'example 1',\n",
+ " 'description': 'an example of metadata for CSV payload',\n",
+ " 'author': 'John'}"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "file_1 = \"example-data.csv\"\n",
+ "payloads = {'p1': (file_1, open(file_1,'rb'))}\n",
+ "\n",
+ "obj_1 = dict()\n",
+ "obj_1[\"name\"] = \"example 1\"\n",
+ "obj_1[\"description\"] = \"an example of metadata for CSV payload\"\n",
+ "obj_1[\"author\"] = \"John\"\n",
+ "\n",
+ "my_acl = dict()\n",
+ "my_acl[\"readers\"] = [\"public\"]\n",
+ "\n",
+ "response = localhost.create(obj_1, obj_type, acls=my_acl, payloads=payloads)\n",
+ "response"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
+ " 'description': 'another example of metadata for CSV payload',\n",
+ " 'author': 'Tim'}"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "file_2 = \"example-data.csv\"\n",
+ "payloads = {'p1': (file_2, open(file_2,'rb'))}\n",
+ "\n",
+ "obj_2 = dict()\n",
+ "obj_2[\"name\"] = \"example 2\"\n",
+ "obj_2[\"description\"] = \"another example of metadata for CSV payload\"\n",
+ "obj_2[\"author\"] = \"Tim\"\n",
+ "\n",
+ "my_acl = dict()\n",
+ "my_acl[\"readers\"] = [\"public\"]\n",
+ "\n",
+ "response = localhost.create(obj_2, obj_type, acls=my_acl, payloads=payloads)\n",
+ "response"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Query objects"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Full text query example"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'pageNum': 0,\n",
+ " 'pageSize': -1,\n",
+ " 'size': 2,\n",
+ " 'results': [{'id': 'test/f1f0188d7e74ce2e9b39',\n",
+ " 'name': 'example 1',\n",
+ " 'description': 'an example of metadata for CSV payload',\n",
+ " 'author': 'John'},\n",
+ " {'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
+ " 'description': 'another example of metadata for CSV payload',\n",
+ " 'author': 'Tim'}]}"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "q = Q('metadata')\n",
+ "my_results = localhost.find(str(q))\n",
+ "my_results"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Field query examples"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'pageNum': 0,\n",
+ " 'pageSize': -1,\n",
+ " 'size': 1,\n",
+ " 'results': [{'id': 'test/f1f0188d7e74ce2e9b39',\n",
+ " 'name': 'example 1',\n",
+ " 'description': 'an example of metadata for CSV payload',\n",
+ " 'author': 'John'}]}"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "q = Q('/author','John')\n",
+ "my_results = localhost.find(str(q))\n",
+ "obj_id_1 = my_results[\"results\"][0][\"id\"]\n",
+ "my_results"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'pageNum': 0,\n",
+ " 'pageSize': -1,\n",
+ " 'size': 1,\n",
+ " 'results': [{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
+ " 'description': 'another example of metadata for CSV payload',\n",
+ " 'author': 'Tim'}]}"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "q = Q('/author','Tim')\n",
+ "my_results = localhost.find(str(q))\n",
+ "obj_id_2 = my_results[\"results\"][0][\"id\"]\n",
+ "my_results"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Read objects"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'test/d92d43a269b89a3e6a10'"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "obj_id_2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
+ " 'description': 'another example of metadata for CSV payload',\n",
+ " 'author': 'Tim'}"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_obj = localhost.read(obj_id_2)\n",
+ "my_obj"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'type': 'Document',\n",
+ " 'content': {'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
+ " 'description': 'another example of metadata for CSV payload',\n",
+ " 'author': 'Tim'},\n",
+ " 'acl': {'readers': ['public']},\n",
+ " 'metadata': {'createdOn': 1652894477383,\n",
+ " 'createdBy': 'admin',\n",
+ " 'modifiedOn': 1652894477383,\n",
+ " 'modifiedBy': 'admin',\n",
+ " 'txnId': 1652894477383052},\n",
+ " 'payloads': [{'name': 'p1',\n",
+ " 'filename': 'example-data.csv',\n",
+ " 'mediaType': 'application/octet-stream',\n",
+ " 'size': 385}]}"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "my_obj = localhost.read(obj_id_2,full=True)\n",
+ "my_obj"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'p1'"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "obj_payload_name = my_obj[\"payloads\"][0][\"name\"]\n",
+ "obj_payload_name"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'\\ufeff\"SAM0\",\"SAM1\"\\r\\n1.00,2.302389071\\r\\n2.00,3.71503899\\r\\n3.00,9.426125622\\r\\n4.00,11.34529125\\r\\n5.00,11.87704484\\r\\n6.00,19.01325695\\r\\n7.00,21.52353652\\r\\n8.00,28.28670056\\r\\n9.00,29.55737761\\r\\n10.00,25.89582707\\r\\n11.00,31.57982065\\r\\n12.00,36.02452105\\r\\n13.00,39.47686412\\r\\n14.00,44.41192202\\r\\n15.00,43.36098819\\r\\n16.00,48.61525381\\r\\n17.00,53.91222295\\r\\n18.00,54.28420278\\r\\n19.00,53.1378195\\r\\n20.00,55.88015939'"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "obj, payload = localhost.read(obj_id_2, getObjPayTuple=True)\n",
+ "payload = payload[obj_payload_name]\n",
+ "payload.decode('utf-8')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " SAM0 | \n",
+ " SAM1 | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 1.0 | \n",
+ " 2.302389 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 2.0 | \n",
+ " 3.715039 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 3.0 | \n",
+ " 9.426126 | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " 4.0 | \n",
+ " 11.345291 | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " 5.0 | \n",
+ " 11.877045 | \n",
+ "
\n",
+ " \n",
+ " 5 | \n",
+ " 6.0 | \n",
+ " 19.013257 | \n",
+ "
\n",
+ " \n",
+ " 6 | \n",
+ " 7.0 | \n",
+ " 21.523537 | \n",
+ "
\n",
+ " \n",
+ " 7 | \n",
+ " 8.0 | \n",
+ " 28.286701 | \n",
+ "
\n",
+ " \n",
+ " 8 | \n",
+ " 9.0 | \n",
+ " 29.557378 | \n",
+ "
\n",
+ " \n",
+ " 9 | \n",
+ " 10.0 | \n",
+ " 25.895827 | \n",
+ "
\n",
+ " \n",
+ " 10 | \n",
+ " 11.0 | \n",
+ " 31.579821 | \n",
+ "
\n",
+ " \n",
+ " 11 | \n",
+ " 12.0 | \n",
+ " 36.024521 | \n",
+ "
\n",
+ " \n",
+ " 12 | \n",
+ " 13.0 | \n",
+ " 39.476864 | \n",
+ "
\n",
+ " \n",
+ " 13 | \n",
+ " 14.0 | \n",
+ " 44.411922 | \n",
+ "
\n",
+ " \n",
+ " 14 | \n",
+ " 15.0 | \n",
+ " 43.360988 | \n",
+ "
\n",
+ " \n",
+ " 15 | \n",
+ " 16.0 | \n",
+ " 48.615254 | \n",
+ "
\n",
+ " \n",
+ " 16 | \n",
+ " 17.0 | \n",
+ " 53.912223 | \n",
+ "
\n",
+ " \n",
+ " 17 | \n",
+ " 18.0 | \n",
+ " 54.284203 | \n",
+ "
\n",
+ " \n",
+ " 18 | \n",
+ " 19.0 | \n",
+ " 53.137819 | \n",
+ "
\n",
+ " \n",
+ " 19 | \n",
+ " 20.0 | \n",
+ " 55.880159 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " SAM0 SAM1\n",
+ "0 1.0 2.302389\n",
+ "1 2.0 3.715039\n",
+ "2 3.0 9.426126\n",
+ "3 4.0 11.345291\n",
+ "4 5.0 11.877045\n",
+ "5 6.0 19.013257\n",
+ "6 7.0 21.523537\n",
+ "7 8.0 28.286701\n",
+ "8 9.0 29.557378\n",
+ "9 10.0 25.895827\n",
+ "10 11.0 31.579821\n",
+ "11 12.0 36.024521\n",
+ "12 13.0 39.476864\n",
+ "13 14.0 44.411922\n",
+ "14 15.0 43.360988\n",
+ "15 16.0 48.615254\n",
+ "16 17.0 53.912223\n",
+ "17 18.0 54.284203\n",
+ "18 19.0 53.137819\n",
+ "19 20.0 55.880159"
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df = pd.read_csv(StringIO(payload.decode('utf-8')))\n",
+ "df"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAX4AAAEGCAYAAABiq/5QAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAAAsTAAALEwEAmpwYAAAV2klEQVR4nO3df7BcdXnH8fdzyTWJTSwhCZgSMLUw7VgHUnqLP6IUoSBSJmCZUm1t49SZTKe1o390CB2n6tg6Am2dWqe1jUpNrRVso02GagsNov0F4w0NUYoadaIE0iSEoNyRXBPu0z/2rNnc7N4fuXt2z93zfs3c2d2ze3YfTpbP/d7vOec5kZlIkupjqN8FSJJ6y+CXpJox+CWpZgx+SaoZg1+SamZBvwuYiRUrVuSaNWv6XYYkzSs7d+58MjNXTl4+L4J/zZo1jI6O9rsMSZpXIuLb7ZY71SNJNWPwS1LNGPySVDMGvyTVjMEvSTVj8EtSRR0eG+fhx57m8Nh4V993XhzOKUl1s23X42zaupvhoSGOTUxw+40XsX7tuV15b0f8klQxh8fG2bR1N0ePTfDM+HGOHpvg5q27uzbyN/glqWL2HXmW4aGT43l4aIh9R57tyvsb/JJUMauXLebYxMRJy45NTLB62eKuvL/BL0kVs3zJQm6/8SIWDQ+xdOECFg0PcfuNF7F8ycKuvL87dyWpjcNj4+w78iyrly3uWuDOxvq157LughWl1GDwS9IkZR5RMxvLlyws5ZeOUz2SBtLpHgNf9hE1VeCIX9LAmcuIvXlEzVFO7FxtHlHTjymfMjjilzRQ5jpi7+YRNWWdeTtXBr+kgTLXY+C7dUTNtl2Ps+62+3jTRx5k3W33sX3X47Nav0xO9UgaKN0Ysc/1iJrWvzqaU0Y3b93NugtWVGK6yBG/pIHSrRH78iULufi8M08rqMs+83auHPFLGjhlHgM/E2WfeTtXjvglDaS5jNi78dllnnk7V474JakE/f6rYyoGvySVpKwzb+fKqR5JqhmDX5JqxuCXpJox+CWpZkrduRsRe4FngOeA45k5EhFnAXcBa4C9wE2ZeaTMOiRJJ/RixP+azFybmSPF41uAHZl5IbCjeCxJ6pF+TPVcD2wp7m8BbuhDDZJUW2UHfwL3RMTOiNhYLDsnM/cDFLdnt1sxIjZGxGhEjB46dKjkMiWpPso+gWtdZj4REWcD90bEV2e6YmZuBjYDjIyMZFkFSlLdlDriz8wnituDwGeAS4EDEbEKoLg9WGYNkuanql7EZBCUNuKPiB8BhjLzmeL+1cB7gO3ABuDW4nZbWTVImp+qcrHzQVXmVM85wGciovk5f5+Z/xIRXwI+FRFvAb4D/HKJNUiaZ6p+EZNBUFrwZ+a3gIvbLD8MXFnW50qa3+pwsfN+88xdSZVS9YuYDAKDX1KlVP0iJoPAfvySKqfKFzEZBAa/pEqq6kVMBoFTPZJUMwa/JNWMwS9JNWPwS1LNGPySVDMGvyTVjMEvSTVj8EtSzRj8ktqyH/7g8sxdSaewH/5gc8Qv6SSt/fCfGT/O0WMT3Lx1tyP/AWLwSzpJsx9+q2Y//Nlwqqi6nOqRdJJu9MN3qqjaHPFLOslc++E7VVR9jvglnWIu/fC9dGL1GfyS2jrdfvheOrH6nOqR1FVeOrH6HPFL6jovnVhtBr+kUnjpxOpyqkeSasbgl6SaMfglqWYMfkmqGYNfkmqm9OCPiDMi4n8i4u7i8VkRcW9E7Clul5VdgyTphF6M+N8GPNry+BZgR2ZeCOwoHkuSeqTU4I+I1cAvAh9pWXw9sKW4vwW4ocwapLqyLbI6KfsErj8DbgaWtiw7JzP3A2Tm/og4u92KEbER2Ahw/vnnl1ymNFhsi6yplDbij4jrgIOZufN01s/MzZk5kpkjK1eu7HJ10uCyLbKmU+aIfx2wPiKuBRYBL4iIvwMORMSqYrS/CjhYYg1S7dgWWdMpbcSfmb+fmaszcw3wBuC+zHwTsB3YULxsA7CtrBqkOrItsqbTj+P4bwWuiog9wFXFY0ldYltkTScys981TGtkZCRHR0f7XYY0rxweG7ctcs1FxM7MHJm83LbM0oCyLbI6sWWDJNWMwS9JNWPwS1LNGPySVDMGvyTVjMEvVZRN1lQWD+eUKsgmayqTI36pYmyyprIZ/FLFNJustWo2WZO6weCXKsYmayqbwS9VjE3WVDZ37koVtH7tuay7YIVN1lQKg1+qKJusqSxO9UhSzRj8klQzBr8k1YzBL0k1Y/BLUs0Y/JJUMwa/JNWMwS9JNWPwSyWxn76q6rTP3I2IqzLz3m4WIw0K++mryuYy4v9o16qQBoj99FV1U474I2J7p6eA5d0vR5r/mv30j3KitXKzn769d1QF0031vBp4EzA2aXkAl5ZSkTTP2U9fVTdd8D8AfD8zvzD5iYj4WjklSfNbs5/+zZPm+B3tqyqmDP7MfN0Uz1021boRsQj4IrCw+Jx/zMx3RcRZwF3AGmAvcFNmHpld2VK12U9fVVbm4ZzjwBWZeTGwFrgmIl4O3ALsyMwLgR3FY6nr+n045fIlC7n4vDMNfVXOdDt3nwGydVHxOIDMzBd0WjczkxP7BoaLnwSuBy4vlm8B7gc2zb50qTMPp5Q6m27EvwP4X+CPgJdm5tLMfEHzdro3j4gzImIXcBC4NzMfBM7JzP0Axe3ZHdbdGBGjETF66NChWfwnqe48nFKa2pTBn5k3AK8FDgEfjogvRMRvF/P008rM5zJzLbAauDQiXjrTwjJzc2aOZObIypUrZ7qa9MPDKVs1D6eUNIM5/sz8bmb+DfA64K+A9wBvns2HZObTNKZ0rgEORMQqgOL24Kwqlqbh4ZTS1KYN/oh4ZUR8EHgIWAe8PjPfP4P1VkbEmcX9xcAvAF8FtgMbipdtALadXukadKe7c7Z5OOWi4SGWLlzAouEhD6eUWky3c3cv8DRwJ7AROF4svwQgMx+aYvVVwJaIOIPGL5hPZebdEfHfwKci4i3Ad4BfnuN/gwbQXHfOejil1Fk0Dr7p8GTE/Zw4qqd5NE9TZuYV5ZV2wsjISI6Ojvbio1QBh8fGWXfbfRw9dmK6ZtHwEP+56QoDXJqFiNiZmSOTl093AtflU7zhcBfqkk5hrxupXLM6gSsaroiIjwD7SqpJNefOWalcMwr+iHhZRHwA+DaNnbP/DvxUmYWpvtw5K5Vrup277wVuorET9pM0DuUczcwtPahNNebOWak803Xn3Ah8DfgQcHdmHo2IznuDpS5avmShgS+VYLqpnhcC7wXWA9+IiI8DiyPitC/ZKEnqr+mO6nkO+BzwuaLN8nXA84F9EXFfZv5qD2qU+uLw2LhTTRpI083x/xzwWGb+XzHN83waXTb/GXikFwVK/WB3Tw2y6aZ6/hr4AUBEXAbcSqOV8hPAK8stTeoPu3tq0E0X/Gdk5lPF/V8BNmfm1sz8A+CCckuT+sPunhp00wZ/y47cK4H7Wp5zB68GkieQadBNF/yfBL4QEduAZ2mcuEVEXAB8t+TapL7wBDINuumO6nlvROyg0WnznjzR0W0I+N2yi5P6xRPINMimna7JzAfaLPt6OeVI1eEJZBpUs2rSJkma/wx+SaoZg1+Sasbgl6SaMfglqWYMfkmqGYNfkmrG4JekmjH4VZrDY+M8/NjTdrWUKsZGayqF/eyl6nLEr66zn71UbQa/us5+9lK1GfzqOvvZS9VWWvBHxHkR8fmIeDQiHomItxXLz4qIeyNiT3G7rKwa1B/2s5eqLU602O/yG0esAlZl5kMRsRTYCdwAvBl4KjNvjYhbgGWZuWmq9xoZGcnR0dFS6lR5Do+N289e6qOI2JmZI5OXl3ZUT2buB/YX95+JiEeBc4HrgcuLl20B7gemDH7NT/azl6qpJ3P8EbEG+BngQeCc4pdC85fD2b2oQZLUUHrwR8QSYCvw9sz83izW2xgRoxExeujQofIKVEeegCUNplJP4IqIYRqh/4nM/HSx+EBErMrM/cV+gIPt1s3MzcBmaMzxl1mnTuUJWNLgKvOongA+Cjyame9veWo7sKG4vwHYVlYNOj2egCUNtjKnetYBvw5cERG7ip9rgVuBqyJiD3BV8VgV4glY0mAr86ie/wCiw9NXlvW5mjtPwJIGm2fu6hSegCUNNrtzqq31a89l3QUrPAFLGkAGvzryBCxpMDnVI0k1Y/BLUs0Y/JJUMwa/JNWMwS9JNWPwS1LNGPySVDMGvyTVjMEvSTVj8EtSzRj8klQzBr8k1YzBL0k1Y/BLUs0Y/JJUMwa/JNWMwS9JNWPwS1LNGPySVDMG/wA7PDbOw489zeGx8X6XIqlCvNj6gNq263E2bd3N8NAQxyYmuP3Gi1i/9tx+lyWpAhzxV9jpjtgPj42zaetujh6b4Jnx4xw9NsHNW3c78pcEOOKvrLmM2PcdeZbhoSGOMvHDZcNDQ+w78izLlywsq2RJ84Qj/gqa64h99bLFHJuYOGnZsYkJVi9bXEa5kuYZg7+CmiP2Vs0R+0wsX7KQ22+8iEXDQyxduIBFw0PcfuNFjvYlASVO9UTEHcB1wMHMfGmx7CzgLmANsBe4KTOPlFXDfNWNEfv6teey7oIV7DvyLKuXLTb0Jf1QmSP+jwHXTFp2C7AjMy8EdhSPNUm3RuzLlyzk4vPONPQlnaS0EX9mfjEi1kxafD1weXF/C3A/sKmsGuYzR+ySytLro3rOycz9AJm5PyLO7vHn99ThsfE5BffyJQsNfEldV9nDOSNiI7AR4Pzzz+9zNbPnCVSSqqrXR/UciIhVAMXtwU4vzMzNmTmSmSMrV67sWYHd4AlUkqqs18G/HdhQ3N8AbOvx5/fEXA/HlKQylRb8EfFJ4L+Bn4yIfRHxFuBW4KqI2ANcVTweOJ5AJanKyjyq540dnrqyrM+siubhmDdPmuN3R62kKqjszt35zsMxJVWVwV8iD8eUVEX26pGkmjH4JalmDH5JqhmDX5JqxuCXpJox+CWpZgx+SaoZg1+Sasbgl6SaMfglqWYMfkmqGYNfkmrG4JekmjH4p3B4bJyHH3vaSyZKGii2Ze7Ai6VLGlSO+NvwYumSBpnB34YXS5c0yAz+NrxYuqRBNtDBf7o7Z5sXS180PMTShQtYNDzkxdIlDYyB3bk7152zXixd0qAayOBv3Tl7lMaUzc1bd7PughWzCnAvli5pEA3kVI87ZyWps4EMfnfOSlJnAxn87pyVpM4Gco4f3DkrSZ0MbPCDO2clqZ2+TPVExDUR8bWI+EZE3NKPGiSprnoe/BFxBvAXwOuAlwBvjIiX9LoOSaqrfoz4LwW+kZnfyswfAHcC1/ehDkmqpX4E/7nAYy2P9xXLThIRGyNiNCJGDx061LPiJGnQ9SP4o82yPGVB5ubMHMnMkZUrV/agLEmqh34c1bMPOK/l8WrgialW2Llz55MR8e1Sqzp9K4An+13EFKxvbqxvbqxv7uZS44vaLYzMUwbbpYqIBcDXgSuBx4EvAb+amY/0tJAuiYjRzBzpdx2dWN/cWN/cWN/clVFjz0f8mXk8It4K/CtwBnDHfA19SZqP+nICV2Z+FvhsPz5bkupuIHv19NjmfhcwDeubG+ubG+ubu67X2PM5fklSfznil6SaMfglqWYM/hmIiPMi4vMR8WhEPBIRb2vzmssj4rsRsav4eWePa9wbEV8uPnu0zfMREX9eNMbbHRGX9LC2n2zZLrsi4nsR8fZJr+np9ouIOyLiYER8pWXZWRFxb0TsKW6XdVi39CaDHer744j4avHv95mIOLPDulN+F0qs790R8XjLv+G1Hdbt1/a7q6W2vRGxq8O6vdh+bTOlZ9/BzPRnmh9gFXBJcX8pjfMQXjLpNZcDd/exxr3Aiimevxb4HI0zp18OPNinOs8A/g94UT+3H3AZcAnwlZZltwO3FPdvAW7rUP83gRcDzwMenvxdKLG+q4EFxf3b2tU3k+9CifW9G/i9Gfz792X7TXr+T4F39nH7tc2UXn0HHfHPQGbuz8yHivvPAI/Spr9QxV0P/G02PACcGRGr+lDHlcA3M7OvZ2Jn5heBpyYtvh7YUtzfAtzQZtWeNBlsV19m3pOZx4uHD9A4670vOmy/mejb9muKiABuAj7Z7c+dqSkypSffQYN/liJiDfAzwINtnn5FRDwcEZ+LiJ/ubWUkcE9E7IyIjW2en1FzvB54A53/h+vn9gM4JzP3Q+N/TODsNq+pynb8TRp/wbUz3XehTG8tpqLu6DBNUYXt92rgQGbu6fB8T7ffpEzpyXfQ4J+FiFgCbAXenpnfm/T0QzSmLy4GPgj8U4/LW5eZl9C4zsHvRMRlk56fUXO8MkXE84D1wD+0ebrf22+mqrAd3wEcBz7R4SXTfRfK8iHgJ4C1wH4a0ymT9X37AW9k6tF+z7bfNJnScbU2y2a1DQ3+GYqIYRr/QJ/IzE9Pfj4zv5eZY8X9zwLDEbGiV/Vl5hPF7UHgMzT+HGw16+Z4JXgd8FBmHpj8RL+3X+FAc/qruD3Y5jV93Y4RsQG4Dvi1LCZ8J5vBd6EUmXkgM5/LzAngwx0+t9/bbwHwS8BdnV7Tq+3XIVN68h00+GegmBP8KPBoZr6/w2teWLyOiLiUxrY93KP6fiQiljbv09gJ+JVJL9sO/EY0vBz4bvNPyh7qONLq5/ZrsR3YUNzfAGxr85ovARdGxI8Xf8G8oVivdBFxDbAJWJ+Z3+/wmpl8F8qqr3Wf0es7fG7ftl/hF4CvZua+dk/2avtNkSm9+Q6Wued6UH6AV9H4U2o3sKv4uRb4LeC3ite8FXiExh72B4BX9rC+Fxef+3BRwzuK5a31BY1LXn4T+DIw0uNt+HwaQf6jLcv6tv1o/ALaDxyjMYJ6C7Ac2AHsKW7PKl77Y8BnW9a9lsZRGN9sbuse1fcNGnO7ze/gX02ur9N3oUf1fbz4bu2mEUSrqrT9iuUfa37nWl7bj+3XKVN68h20ZYMk1YxTPZJUMwa/JNWMwS9JNWPwS1LNGPySVDMGv9QiIt5RdEvcXXRnfFmxfEFEPBkR75v0+vsj4jvNcxCKZf8UEWMtjzcU3Rb3FCdgSX1l8EuFiHgFjbNiL8nMi2ic7NPsiXI18DXgptaQLzwNrCve40wanReb73kW8C7gZTTOAH1Xp1a7Uq8Y/NIJq4AnM3McIDOfzOL0fRpnHX8A+A6Nttat7qRx9iQ02gG0tvR4LXBvZj6VmUeAe4FrSqpfmhGDXzrhHuC8iPh6RPxlRPw8QEQsptFO+m4aZ4S+cdJ6O4DLIuIMGr8AWvvAVKEbpXQSg18qZKNJ3M8CG4FDwF0R8WYa0z+fz0Z/nK3A64uQb3oO+A/gV4DFmbm35bkqdKOUTrKg3wVIVZKZzwH3A/dHxJdpNMo6BqyLiL3Fy5YDrwH+rWXVO2l0cnz3pLfcR+PqYk2ri/eX+sYRv1SIxrWBL2xZtJbGyP9VwPmZuSYz1wC/w6nTPf8OvI9Tu4/+K3B1RCwrdupeXSyT+sYRv3TCEuCDxZE5x2l0w/wv4PnNHb6FbcDtEbGwuSAb3Q7/ZPIbZuZTEfGHNFrpArwnM0/nkoVS19idU5JqxqkeSaoZg1+Sasbgl6SaMfglqWYMfkmqGYNfkmrG4Jekmvl/JcEqvrlJZPoAAAAASUVORK5CYII=\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "df.plot.scatter(x='SAM0', y='SAM1')\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Update Objects\n",
+ "\n",
+ "This also demonstrates the use of \"Dry Run\". During a \"Dry Run\", Cordra not actually create/update the object. Cordra will return results as if object had been created/updated. "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Update part of the object JSON\n",
+ "\n",
+ "payloads not affected"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'type': 'Document',\n",
+ " 'content': {'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
+ " 'description': 'I really need to write a better description for my data.',\n",
+ " 'author': 'Tim'},\n",
+ " 'acl': {'readers': ['public']},\n",
+ " 'metadata': {'createdOn': 1652894477383,\n",
+ " 'createdBy': 'admin',\n",
+ " 'modifiedOn': 1652894477858,\n",
+ " 'modifiedBy': 'admin',\n",
+ " 'txnId': 1652894477383052},\n",
+ " 'payloads': [{'name': 'p1',\n",
+ " 'filename': 'example-data.csv',\n",
+ " 'mediaType': 'application/octet-stream',\n",
+ " 'size': 385}]}"
+ ]
+ },
+ "execution_count": 17,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "response = localhost.update(\n",
+ " \"I really need to write a better description for my data.\",\n",
+ " obj_id_2,\n",
+ " jsonPointer=\"/description\",\n",
+ " dryRun=True,\n",
+ " full=True)\n",
+ "response"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Update all of the object JSON\n",
+ "\n",
+ "payloads not affected"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{'id': 'test/3b11b6a7bdb1d6cf052e', 'SAM1': 'Level of CXCR4 expression'}\n",
+ "{'id': 'test/d92d43a269b89a3e6a10', 'SAM1': 'Level of CXCR4 expression'}\n"
+ ]
+ }
+ ],
+ "source": [
+ "original = {'id': 'test/3b11b6a7bdb1d6cf052e', \"SAM1\":\"Level of CXCR4 expression\"}\n",
+ "\n",
+ "response = localhost.update(\n",
+ " original,\n",
+ " obj_id_2,\n",
+ " dryRun=True,\n",
+ " full=True)\n",
+ "\n",
+ "print(original)\n",
+ "print(response[\"content\"])\n",
+ "\n",
+ "# assert original == response[\"content\"]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Check ACLs"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Create new user\n",
+ "user1 = localhost.create({\"@context\": \"\", \"@type\": \"\", \"username\": \"user1\", \"password\": \"person.1234\"}, \"User\")\n",
+ "user1_id = user1[\"id\"]\n",
+ "\n",
+ "user2 = localhost.create({\"@context\": \"\", \"@type\": \"\", \"username\": \"user2\", \"password\": \"person.1234\"}, \"User\")\n",
+ "user2_id = user2[\"id\"]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[{'id': 'test/48baeedf9a39614b710c', 'type': 'Document', 'content': {'id': 'test/48baeedf9a39614b710c', 'name': 'unaccessible'}, 'metadata': {'createdOn': 1652894478082, 'createdBy': 'admin', 'modifiedOn': 1652894478082, 'modifiedBy': 'admin', 'txnId': 1652894478082055}}, {'readers': ['test/b3daa77b4c04a9551b87']}]\n",
+ "{'id': 'test/b3daa77b4c04a9551b87', 'username': 'user1', 'password': '', '@context': '', '@type': ''}\n",
+ "{'id': 'test/a1881c06eec96db9901c', 'username': 'user2', 'password': '', '@context': '', '@type': ''}\n",
+ "{'message': 'Forbidden'}\n",
+ "403 Client Error: Forbidden for url: https://localhost:8443/objects/test/48baeedf9a39614b710c?full=False\n"
+ ]
+ }
+ ],
+ "source": [
+ "r = localhost.create({\"name\": \"unaccessible\"}, obj_type, acls={\"readers\":[user1_id],\"writers\":None})\n",
+ "obj_id = r[0]['id']\n",
+ "\n",
+ "print(r)\n",
+ "print(user1)\n",
+ "print(user2)\n",
+ "\n",
+ "localhost_user1 = cordra.CordraClient(host=host, username=\"user1\", password=\"person.1234\", verify=False)\n",
+ "localhost_user1.read(obj_id)\n",
+ "\n",
+ "localhost_user2 = cordra.CordraClient(host=host, username=\"user2\", password=\"person.1234\", verify=False)\n",
+ "\n",
+ "# this should return a 403 error\n",
+ "try:\n",
+ " localhost_user2.read(obj_id)\n",
+ "except Exception as e:\n",
+ " print(e)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Update ACLs"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{'message': 'Forbidden'}\n",
+ "403 Client Error: Forbidden for url: https://localhost:8443/objects/test/48baeedf9a39614b710c?full=False\n"
+ ]
+ }
+ ],
+ "source": [
+ "r = localhost.update(dict(), obj_id, acls={\"readers\":[user2_id],\"writers\":None})\n",
+ "\n",
+ "localhost_user2.read(obj_id)\n",
+ "\n",
+ "# this should return a 403 error\n",
+ "try:\n",
+ " localhost_user1.read(obj_id)\n",
+ "except Exception as e: \n",
+ " print(e)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{'message': 'Forbidden'}\n",
+ "403 Client Error: Forbidden for url: https://localhost:8443/objects/test/48baeedf9a39614b710c?full=False\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Update payloads and acls at the same time\n",
+ "r = localhost.update({\"@id\": obj_id}, obj_id, payloads={\"file\":\"update\".encode('utf-8')}, acls={\"readers\":[user1_id],\"writers\":None})\n",
+ "\n",
+ "localhost_user1.read(obj_id)\n",
+ "\n",
+ "# this should return a 403 error\n",
+ "try:\n",
+ " localhost_user2.read(obj_id)\n",
+ "except Exception as e:\n",
+ " print(e)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Delete objects"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "5\n"
+ ]
+ }
+ ],
+ "source": [
+ "all_objects = []\n",
+ "\n",
+ "r = localhost.find(\"*\", pageSize=-1, full=True)\n",
+ "\n",
+ "all_objects += [ri['id'] for ri in r['results'] if ri['type']!='Schema']\n",
+ " \n",
+ "print(len(all_objects))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for obj_id in all_objects:\n",
+ " localhost.delete(obj_id)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Delete Token"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'active': False}"
+ ]
+ },
+ "execution_count": 25,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "r = localhost.delete_auth()\n",
+ "r"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/examples/examples-token.ipynb b/examples/examples-token.ipynb
index 71ce6d0..e146b84 100644
--- a/examples/examples-token.ipynb
+++ b/examples/examples-token.ipynb
@@ -4,12 +4,23 @@
"cell_type": "code",
"execution_count": 1,
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/home/sven/7/Work/ThesisMatData/CordraPy/cordra/cordra.py:67: UserWarning: CordraObject may be moved to a new module with a new name in future releases.\n",
+ " warn(\"CordraObject may be moved to a new module with a new name in future releases.\")\n",
+ "/home/sven/7/Work/ThesisMatData/CordraPy/cordra/cordra.py:376: UserWarning: Token may be moved to a new module with a new name in future releases.\n",
+ " warn(\"Token may be moved to a new module with a new name in future releases.\")\n"
+ ]
+ }
+ ],
"source": [
"import getpass\n",
"import cordra\n",
"from lucenequerybuilder import Q\n",
- "from io import StringIO\n",
+ "from io import StringIO, BytesIO\n",
"import pandas as pd\n",
"import matplotlib.pyplot as plt"
]
@@ -27,8 +38,8 @@
"metadata": {},
"outputs": [],
"source": [
- "host = \"https://127.0.0.1\"\n",
- "obj_type = \"debug\""
+ "host = \"https://127.0.0.1:8443\"\n",
+ "obj_type = \"Document\""
]
},
{
@@ -52,7 +63,7 @@
}
],
"source": [
- "username = \"testuser1\"\n",
+ "username = \"admin\"\n",
"password = getpass.getpass()"
]
},
@@ -71,11 +82,11 @@
{
"data": {
"text/plain": [
- "{'access_token': '16wmt3rhwp6mk1a0itsl6c576',\n",
+ "{'access_token': 'pva8e9zmdtg5ysv0orshmmqq',\n",
" 'token_type': 'Bearer',\n",
" 'active': True,\n",
- " 'userId': 'local/bc51a83eea09846dc024',\n",
- " 'username': 'testuser1'}"
+ " 'userId': 'admin',\n",
+ " 'username': 'admin'}"
]
},
"execution_count": 4,
@@ -103,7 +114,8 @@
{
"data": {
"text/plain": [
- "{'name': 'example 1',\n",
+ "{'id': 'test/f1f0188d7e74ce2e9b39',\n",
+ " 'name': 'example 1',\n",
" 'description': 'an example of metadata for CSV payload',\n",
" 'author': 'John'}"
]
@@ -144,7 +156,8 @@
{
"data": {
"text/plain": [
- "{'name': 'example 2',\n",
+ "{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
" 'description': 'another example of metadata for CSV payload',\n",
" 'author': 'Tim'}"
]
@@ -202,30 +215,38 @@
"{'pageNum': 0,\n",
" 'pageSize': -1,\n",
" 'size': 2,\n",
- " 'results': [{'id': 'local/f6d4cf0f7db6230fff12',\n",
- " 'type': 'debug',\n",
- " 'content': {'name': 'example 1',\n",
+ " 'results': [{'id': 'test/f1f0188d7e74ce2e9b39',\n",
+ " 'type': 'Document',\n",
+ " 'content': {'id': 'test/f1f0188d7e74ce2e9b39',\n",
+ " 'name': 'example 1',\n",
" 'description': 'an example of metadata for CSV payload',\n",
" 'author': 'John'},\n",
" 'acl': {'readers': ['public']},\n",
- " 'metadata': {'createdOn': 1612797369560,\n",
- " 'createdBy': 'local/bc51a83eea09846dc024',\n",
- " 'modifiedOn': 1612797369560,\n",
- " 'modifiedBy': 'local/bc51a83eea09846dc024',\n",
- " 'txnId': 1612797369560040},\n",
- " 'payloads': [{'name': 'p1', 'filename': 'example-data.csv', 'size': 385}]},\n",
- " {'id': 'local/ff16115bd3c7163a6e8e',\n",
- " 'type': 'debug',\n",
- " 'content': {'name': 'example 2',\n",
+ " 'metadata': {'createdOn': 1652894195999,\n",
+ " 'createdBy': 'admin',\n",
+ " 'modifiedOn': 1652894195999,\n",
+ " 'modifiedBy': 'admin',\n",
+ " 'txnId': 1652894195999027},\n",
+ " 'payloads': [{'name': 'p1',\n",
+ " 'filename': 'example-data.csv',\n",
+ " 'mediaType': 'application/octet-stream',\n",
+ " 'size': 385}]},\n",
+ " {'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'type': 'Document',\n",
+ " 'content': {'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
" 'description': 'another example of metadata for CSV payload',\n",
" 'author': 'Tim'},\n",
" 'acl': {'readers': ['public']},\n",
- " 'metadata': {'createdOn': 1612797369664,\n",
- " 'createdBy': 'local/bc51a83eea09846dc024',\n",
- " 'modifiedOn': 1612797369664,\n",
- " 'modifiedBy': 'local/bc51a83eea09846dc024',\n",
- " 'txnId': 1612797369664041},\n",
- " 'payloads': [{'name': 'p1', 'filename': 'example-data.csv', 'size': 385}]}]}"
+ " 'metadata': {'createdOn': 1652894196042,\n",
+ " 'createdBy': 'admin',\n",
+ " 'modifiedOn': 1652894196042,\n",
+ " 'modifiedBy': 'admin',\n",
+ " 'txnId': 1652894196042028},\n",
+ " 'payloads': [{'name': 'p1',\n",
+ " 'filename': 'example-data.csv',\n",
+ " 'mediaType': 'application/octet-stream',\n",
+ " 'size': 385}]}]}"
]
},
"execution_count": 7,
@@ -257,18 +278,22 @@
"{'pageNum': 0,\n",
" 'pageSize': -1,\n",
" 'size': 1,\n",
- " 'results': [{'id': 'local/f6d4cf0f7db6230fff12',\n",
- " 'type': 'debug',\n",
- " 'content': {'name': 'example 1',\n",
+ " 'results': [{'id': 'test/f1f0188d7e74ce2e9b39',\n",
+ " 'type': 'Document',\n",
+ " 'content': {'id': 'test/f1f0188d7e74ce2e9b39',\n",
+ " 'name': 'example 1',\n",
" 'description': 'an example of metadata for CSV payload',\n",
" 'author': 'John'},\n",
" 'acl': {'readers': ['public']},\n",
- " 'metadata': {'createdOn': 1612797369560,\n",
- " 'createdBy': 'local/bc51a83eea09846dc024',\n",
- " 'modifiedOn': 1612797369560,\n",
- " 'modifiedBy': 'local/bc51a83eea09846dc024',\n",
- " 'txnId': 1612797369560040},\n",
- " 'payloads': [{'name': 'p1', 'filename': 'example-data.csv', 'size': 385}]}]}"
+ " 'metadata': {'createdOn': 1652894195999,\n",
+ " 'createdBy': 'admin',\n",
+ " 'modifiedOn': 1652894195999,\n",
+ " 'modifiedBy': 'admin',\n",
+ " 'txnId': 1652894195999027},\n",
+ " 'payloads': [{'name': 'p1',\n",
+ " 'filename': 'example-data.csv',\n",
+ " 'mediaType': 'application/octet-stream',\n",
+ " 'size': 385}]}]}"
]
},
"execution_count": 8,
@@ -294,18 +319,22 @@
"{'pageNum': 0,\n",
" 'pageSize': -1,\n",
" 'size': 1,\n",
- " 'results': [{'id': 'local/ff16115bd3c7163a6e8e',\n",
- " 'type': 'debug',\n",
- " 'content': {'name': 'example 2',\n",
+ " 'results': [{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'type': 'Document',\n",
+ " 'content': {'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
" 'description': 'another example of metadata for CSV payload',\n",
" 'author': 'Tim'},\n",
" 'acl': {'readers': ['public']},\n",
- " 'metadata': {'createdOn': 1612797369664,\n",
- " 'createdBy': 'local/bc51a83eea09846dc024',\n",
- " 'modifiedOn': 1612797369664,\n",
- " 'modifiedBy': 'local/bc51a83eea09846dc024',\n",
- " 'txnId': 1612797369664041},\n",
- " 'payloads': [{'name': 'p1', 'filename': 'example-data.csv', 'size': 385}]}]}"
+ " 'metadata': {'createdOn': 1652894196042,\n",
+ " 'createdBy': 'admin',\n",
+ " 'modifiedOn': 1652894196042,\n",
+ " 'modifiedBy': 'admin',\n",
+ " 'txnId': 1652894196042028},\n",
+ " 'payloads': [{'name': 'p1',\n",
+ " 'filename': 'example-data.csv',\n",
+ " 'mediaType': 'application/octet-stream',\n",
+ " 'size': 385}]}]}"
]
},
"execution_count": 9,
@@ -335,7 +364,7 @@
{
"data": {
"text/plain": [
- "'local/ff16115bd3c7163a6e8e'"
+ "'test/d92d43a269b89a3e6a10'"
]
},
"execution_count": 10,
@@ -355,7 +384,8 @@
{
"data": {
"text/plain": [
- "{'name': 'example 2',\n",
+ "{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
" 'description': 'another example of metadata for CSV payload',\n",
" 'author': 'Tim'}"
]
@@ -378,18 +408,22 @@
{
"data": {
"text/plain": [
- "{'id': 'local/ff16115bd3c7163a6e8e',\n",
- " 'type': 'debug',\n",
- " 'content': {'name': 'example 2',\n",
+ "{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'type': 'Document',\n",
+ " 'content': {'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
" 'description': 'another example of metadata for CSV payload',\n",
" 'author': 'Tim'},\n",
" 'acl': {'readers': ['public']},\n",
- " 'metadata': {'createdOn': 1612797369664,\n",
- " 'createdBy': 'local/bc51a83eea09846dc024',\n",
- " 'modifiedOn': 1612797369664,\n",
- " 'modifiedBy': 'local/bc51a83eea09846dc024',\n",
- " 'txnId': 1612797369664041},\n",
- " 'payloads': [{'name': 'p1', 'filename': 'example-data.csv', 'size': 385}]}"
+ " 'metadata': {'createdOn': 1652894196042,\n",
+ " 'createdBy': 'admin',\n",
+ " 'modifiedOn': 1652894196042,\n",
+ " 'modifiedBy': 'admin',\n",
+ " 'txnId': 1652894196042028},\n",
+ " 'payloads': [{'name': 'p1',\n",
+ " 'filename': 'example-data.csv',\n",
+ " 'mediaType': 'application/octet-stream',\n",
+ " 'size': 385}]}"
]
},
"execution_count": 12,
@@ -431,7 +465,7 @@
{
"data": {
"text/plain": [
- "'\\ufeff\"SAM0\",\"SAM1\"\\r\\n1.00,2.302389071\\r\\n2.00,3.71503899\\r\\n3.00,9.426125622\\r\\n4.00,11.34529125\\r\\n5.00,11.87704484\\r\\n6.00,19.01325695\\r\\n7.00,21.52353652\\r\\n8.00,28.28670056\\r\\n9.00,29.55737761\\r\\n10.00,25.89582707\\r\\n11.00,31.57982065\\r\\n12.00,36.02452105\\r\\n13.00,39.47686412\\r\\n14.00,44.41192202\\r\\n15.00,43.36098819\\r\\n16.00,48.61525381\\r\\n17.00,53.91222295\\r\\n18.00,54.28420278\\r\\n19.00,53.1378195\\r\\n20.00,55.88015939'"
+ "b'\\xef\\xbb\\xbf\"SAM0\",\"SAM1\"\\r\\n1.00,2.302389071\\r\\n2.00,3.71503899\\r\\n3.00,9.426125622\\r\\n4.00,11.34529125\\r\\n5.00,11.87704484\\r\\n6.00,19.01325695\\r\\n7.00,21.52353652\\r\\n8.00,28.28670056\\r\\n9.00,29.55737761\\r\\n10.00,25.89582707\\r\\n11.00,31.57982065\\r\\n12.00,36.02452105\\r\\n13.00,39.47686412\\r\\n14.00,44.41192202\\r\\n15.00,43.36098819\\r\\n16.00,48.61525381\\r\\n17.00,53.91222295\\r\\n18.00,54.28420278\\r\\n19.00,53.1378195\\r\\n20.00,55.88015939'"
]
},
"execution_count": 14,
@@ -476,102 +510,102 @@
" \n",
" \n",
" \n",
- " 0 | \n",
+ " 0 | \n",
" 1.0 | \n",
" 2.302389 | \n",
"
\n",
" \n",
- " 1 | \n",
+ " 1 | \n",
" 2.0 | \n",
" 3.715039 | \n",
"
\n",
" \n",
- " 2 | \n",
+ " 2 | \n",
" 3.0 | \n",
" 9.426126 | \n",
"
\n",
" \n",
- " 3 | \n",
+ " 3 | \n",
" 4.0 | \n",
" 11.345291 | \n",
"
\n",
" \n",
- " 4 | \n",
+ " 4 | \n",
" 5.0 | \n",
" 11.877045 | \n",
"
\n",
" \n",
- " 5 | \n",
+ " 5 | \n",
" 6.0 | \n",
" 19.013257 | \n",
"
\n",
" \n",
- " 6 | \n",
+ " 6 | \n",
" 7.0 | \n",
" 21.523537 | \n",
"
\n",
" \n",
- " 7 | \n",
+ " 7 | \n",
" 8.0 | \n",
" 28.286701 | \n",
"
\n",
" \n",
- " 8 | \n",
+ " 8 | \n",
" 9.0 | \n",
" 29.557378 | \n",
"
\n",
" \n",
- " 9 | \n",
+ " 9 | \n",
" 10.0 | \n",
" 25.895827 | \n",
"
\n",
" \n",
- " 10 | \n",
+ " 10 | \n",
" 11.0 | \n",
" 31.579821 | \n",
"
\n",
" \n",
- " 11 | \n",
+ " 11 | \n",
" 12.0 | \n",
" 36.024521 | \n",
"
\n",
" \n",
- " 12 | \n",
+ " 12 | \n",
" 13.0 | \n",
" 39.476864 | \n",
"
\n",
" \n",
- " 13 | \n",
+ " 13 | \n",
" 14.0 | \n",
" 44.411922 | \n",
"
\n",
" \n",
- " 14 | \n",
+ " 14 | \n",
" 15.0 | \n",
" 43.360988 | \n",
"
\n",
" \n",
- " 15 | \n",
+ " 15 | \n",
" 16.0 | \n",
" 48.615254 | \n",
"
\n",
" \n",
- " 16 | \n",
+ " 16 | \n",
" 17.0 | \n",
" 53.912223 | \n",
"
\n",
" \n",
- " 17 | \n",
+ " 17 | \n",
" 18.0 | \n",
" 54.284203 | \n",
"
\n",
" \n",
- " 18 | \n",
+ " 18 | \n",
" 19.0 | \n",
" 53.137819 | \n",
"
\n",
" \n",
- " 19 | \n",
+ " 19 | \n",
" 20.0 | \n",
" 55.880159 | \n",
"
\n",
@@ -609,7 +643,7 @@
}
],
"source": [
- "df = pd.read_csv(StringIO(payload))\n",
+ "df = pd.read_csv(BytesIO(payload))\n",
"df"
]
},
@@ -620,7 +654,7 @@
"outputs": [
{
"data": {
- "image/png": "iVBORw0KGgoAAAANSUhEUgAAAX4AAAEGCAYAAABiq/5QAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAWH0lEQVR4nO3df5Cd9V3o8fdnyZJgE01IAqYJMdRgtb0DEffWenOtFWxFrKGKrdDqTRWNztg77bV3EpyO2uu92oJjdXRqNbYdU6ctYFMMduoVLhSr91raDYYUBAtUeglEEkJoyUi2SffjH8+zzcnhnD272X3OefY879fMzjnn+XGezz45+8n3fJ/v9/NEZiJJao6RQQcgSeovE78kNYyJX5IaxsQvSQ1j4pekhlk06ABmYtWqVblhw4ZBhyFJC8revXufzszV7csXROLfsGED4+Pjgw5DkhaUiPhyp+V29UhSw5j4JalhTPyS1DAmfklqGBO/JDWMiV+SaujIsQnue/xZjhybmPf3XhDDOSWpSfbse4Idu/czOjLCiclJbrz6YrZsWjtv72+LX5Jq5MixCXbs3s/xE5M8N3GS4ycm2b57/7y2/E38klQjB44+z+jI6al5dGSEA0efn7djmPglqUbWrTiHE5OTpy07MTnJuhXnzNsxTPySVCMrly7mxqsvZsnoCMsWL2LJ6Ag3Xn0xK5cunrdjeHFXkjo4cmyCA0efZ92Kc+Y16c7Elk1r2bxxVWXHN/FLUpuqR9XMxMqliyv7D8euHklD6UzHwfdjVM2g2eKXNHTm0mKfGlVznFMXWKdG1fS7y6cqtvglDZW5ttjna1RNlTNv58rEL2mozHUc/HyMqtmz7wk233AXP/2Be9h8w13ctu+JWf0OVbOrR9JQmY8W+1xG1bR+45jqLtq+ez+bN66qTVeRLX5JQ2W+xsGvXLqYSy5YPuv9+jHzdq5s8UsaOlWPg59OP2bezpUtfklD6Uxb7PNx3Kpn3s6VLX5JmmeD/MYxEyZ+SapAlTNv58quHklqGBO/JDWMiV+SGsbEL0kNU+nF3Yh4DHgO+DpwMjPHIuJc4GZgA/AY8MbMPFplHJKkU/rR4v/BzNyUmWPl6+uBOzPzIuDO8rUkqU8G0dVzFbCrfL4LeP0AYpCkxqo68Sdwe0TsjYht5bLzM/MgQPl4XqcdI2JbRIxHxPjhw4crDlOSmqPqCVybM/PJiDgPuCMiHprpjpm5E9gJMDY2llUFKElNU2mLPzOfLB8PAbcCrwCeiog1AOXjoSpjkLQw1flGJgtdZS3+iHgRMJKZz5XPXwv8JnAbsBV4T/m4p6oYJC1MdbjZ+TCrsqvnfODWiJg6zkcz839HxOeBWyLiOuD/A2+oMAZJC8xCuJHJQldZ4s/MLwGXdFh+BLi8quNKWtiacLPzQXPmrqRaWQg3MlnoTPySamUh3MhkobMev6TaqfuNTBY6E7+kWqrzjUwWOrt6JKlhTPyS1DAmfklqGBO/JDWMiV+SGsbEL0kNY+KXpIYx8UtSw5j4JXVkPfzh5cxdSS9gPfzhZotf0mla6+E/N3GS4ycm2b57vy3/IWLil3SaqXr4rabq4c+GXUX1ZVePpNPMRz18u4rqzRa/pNPMtR6+XUX1Z4tf0gvMpR6+t06sPxO/pI7OtB6+t06sP7t6JM0rb51Yf7b4Jc07b51YbyZ+SZXw1on1ZVePJDWMiV+SGsbEL0kNY+KXpIYx8UtSw1Se+CPirIj4x4j4ZPn6woi4JyIejoibI+LsqmOQJJ3Sjxb/24AHW17fAPxeZl4EHAWu60MMkqRSpYk/ItYBPwp8oHwdwGXAx8tNdgGvrzIGqaksi6xuqp7A9fvAdmBZ+Xol8GxmnixfHwA61mqNiG3ANoD169dXHKY0XCyLrOlU1uKPiNcBhzJzb+viDptmp/0zc2dmjmXm2OrVqyuJURpGlkVWL1W2+DcDWyLiSmAJ8M0U3wCWR8SistW/DniywhikxrEssnqprMWfmb+amesycwNwDXBXZr4Z+DTwk+VmW4E9VcUgNZFlkdXLIMbx7wB+JSIeoejz/+AAYpCGlmWR1Utkduxir5WxsbEcHx8fdBjSgnLk2IRlkRsuIvZm5lj7cssyS0PKssjqxpINktQwJn5JahgTvyQ1jIlfkhrGxC9JDWPil2rKImuqisM5pRqyyJqqZItfqhmLrKlqJn6pZqaKrLWaKrImzQcTv1QzFllT1Uz8Us1YZE1V8+KuVENbNq1l88ZVFllTJUz8Uk1ZZE1VsatHkhrGxC9JDWPil6SGMfFLUsOY+CWpYUz8ktQwJn5JahgTvyQ1jIlfqoj19FVXZzxzNyK+MzMfms9gpGFhPX3V2Vxa/LfPWxTSELGevupu2hZ/RPxBt1XA8vkPR1r4purpH+dUaeWpevrW3lEd9Orq+VngHUCnpsq18x+OtPBZT1911yvxfx64PzP/X/uKiHhXJRFJC9xUPf3tbX38tvZVF70S/08CxzutyMwLp9sxIpYAnwEWl8f5eGb+RkRcCNwEnAvcC/xMZn5ttoFLdWY9fdXZtBd3M/OZzPy3M3zvCeCyzLwE2ARcERGvBG4Afi8zLwKOAted4ftL0xr0cMqVSxdzyQXLTfqqnV4Xd/d3WwVkZl7cbd/MTOBY+XK0/EngMuBN5fJdwLuA9888ZKk3h1NK3fXq6pmkSNYfBf4KeH42bx4RZwF7gY3A+4BHgWcz82S5yQGg419jRGwDtgGsX79+NodVw7UOp5waWbN99342b1xl61uid1fPJorRO0spkv9vAS8HnsjML/d688z8evke64BXAN/VabMu++7MzLHMHFu9enWvQ0nfMDWcstXUcEpJM5jAlZkPZeZvZOalFK3+DwP/bTYHycxngbuBVwLLI2Lqm8Y64MlZRSz14HBKaXo9E39ErI2Id0TE3wM/TZH0e/bJR8TqiFhePj8H+CHgQeDTFKOFALYCe84wdg25M704OzWccsnoCMsWL2LJ6IjDKaUWvS7u/i2wDLgFeAvwTLnq7Ig4NzOf6bYvsAbYVfbzjwC3ZOYnI+KfgJsi4n8B/wh8cI6/g4bQXC/OOpxS6i6KwTddVkY8xqk++NYNp0b1vKS60E4ZGxvL8fHxfhxKNXDk2ASbb7iL4ydOddcsGR3h/+64zAQuzUJE7M3Msfbl07b4M3NDZRFJXVjrRqrWrKtzRsS3R8Q7I+L+KgKSvDgrVWtGiT8i1kTE2yPic8ADFN8ULNKmSnhxVqpWr4u7v0CR4NdRXOD9eWBPZv6PPsSmBvPirFSdXjN33wf8A/CmzBwHiIjuV4OlebRy6WITvlSBXon/xcAbgPdGxPkUrf7RyqOSJFWmV8mGpzPz/Zn5KuBy4CvAoYh4MCJ+uy8RSgMy6OqeUlV69fH/R+DxzPzXzDwQEYeBJ8r9lvYjQGkQrO6pYdZrVM+fAF8DiIhXAe+mKKW8l6IbSBo63ixdw65X4j+rpSzDTwE7M3N3Zv4aRallaehY3VPDrmfib6mkeTlwV8u6XheGpQXJCWQadr0S/8eAv42IPRQ3Yfk7gIjYSHGhVxo6TiDTsOtVq+e3IuJOikqbt+epim4jwH+tOjhpUJxApmHWs7smMz/bYdkXqwlHqg8nkGlYzbpImyRpYTPxS1LDmPglqWFM/JLUMCZ+SWoYE78kNYyJX5IaxsQvSQ1j4ldlrGcv1ZOF1lQJ69lL9WWLX/POevZSvZn4Ne+sZy/Vm4lf88569lK9VZb4I+KCiPh0eWP2ByLibeXycyPijoh4uHxcUVUMGgzr2Uv1FqdK7M/zG0esAdZk5r0RsYziPr2vB94CPJOZ74mI64EVmbljuvcaGxvL8fHxSuJUdY4cm7CevTRAEbE3M8fal1c2qiczDwIHy+fPRcSDwFrgKuDV5Wa7gLuBaRO/Fibr2Uv11Jc+/ojYAHw3cA9wfvmfwtR/Duf1IwZJUqHyxB8RS4HdwNsz86uz2G9bRIxHxPjhw4erC1BdOQFLGk6VTuCKiFGKpP+RzPxEufipiFiTmQfL6wCHOu2bmTuBnVD08VcZp17ICVjS8KpyVE8AHwQezMz3tqy6DdhaPt8K7KkqBp0ZJ2BJw63Krp7NwM8Al0XEvvLnSuA9wGsi4mHgNeVr1YgTsKThVuWonr8Hosvqy6s6rubOCVjScHPmrl7ACVjScLM6pzrasmktmzeucgKWNIRM/OrKCVjScLKrR5IaxsQvSQ1j4pekhjHxS1LDmPglqWFM/JLUMCZ+SWoYE78kNYyJX5IaxsQvSQ1j4pekhjHxS1LDmPglqWFM/JLUMCZ+SWoYE78kNYyJX5IaxsQvSQ1j4pekhjHxD7Ejxya47/FnOXJsYtChSKoRb7Y+pPbse4Idu/czOjLCiclJbrz6YrZsWjvosCTVgC3+GjvTFvuRYxPs2L2f4ycmeW7iJMdPTLJ9935b/pIAW/y1NZcW+4GjzzM6MsJxJr+xbHRkhANHn2fl0sVVhSxpgbDFX0NzbbGvW3EOJyYnT1t2YnKSdSvOqSJcSQuMib+GplrsraZa7DOxculibrz6YpaMjrBs8SKWjI5w49UX29qXBFTY1RMRHwJeBxzKzP9QLjsXuBnYADwGvDEzj1YVw0I1Hy32LZvWsnnjKg4cfZ51K84x6Uv6hipb/H8GXNG27Hrgzsy8CLizfK0289ViX7l0MZdcsNykL+k0lbX4M/MzEbGhbfFVwKvL57uAu4EdVcWwkNlil1SVfo/qOT8zDwJk5sGIOK/bhhGxDdgGsH79+j6FN7+OHJuYU+JeuXSxCV/SvKvtcM7M3AnsBBgbG8sBhzNrTqCSVFf9HtXzVESsASgfD/X5+H3hBCpJddbvxH8bsLV8vhXY0+fj98Vch2NKUpUqS/wR8THgH4CXRsSBiLgOeA/wmoh4GHhN+XroOIFKUp1VOarn2i6rLq/qmHUxNRxze1sfvxdqJdVBbS/uLnQOx5RUVyb+CjkcU1IdWatHkhrGxC9JDWPil6SGMfFLUsOY+CWpYUz8ktQwJn5JahgTvyQ1jIlfkhrGxC9JDWPil6SGMfFLUsOY+CWpYUz80zhybIL7Hn/WWyZKGiqWZe7Cm6VLGla2+DvwZumShpmJvwNvli5pmJn4O/Bm6ZKG2VAn/jO9ODt1s/QloyMsW7yIJaMj3ixd0tAY2ou7c704683SJQ2roUz8rRdnj1N02WzfvZ/NG1fNKoF7s3RJw2gou3q8OCtJ3Q1l4vfirCR1N5SJ34uzktTdUPbxgxdnJamboU384MVZSepkIF09EXFFRPxzRDwSEdcPIgZJaqq+J/6IOAt4H/AjwMuAayPiZf2OQ5KaahAt/lcAj2TmlzLza8BNwFUDiEOSGmkQiX8t8HjL6wPlstNExLaIGI+I8cOHD/ctOEkadoNI/NFhWb5gQebOzBzLzLHVq1f3ISxJaoZBjOo5AFzQ8nod8OR0O+zdu/fpiPhypVGduVXA04MOYhrGNzfGNzfGNzdzje/bOi2MzBc0tisVEYuALwKXA08AnwfelJkP9DWQeRIR45k5Nug4ujG+uTG+uTG+uakqvr63+DPzZES8Ffgb4CzgQws16UvSQjSQCVyZ+SngU4M4tiQ13VDW6umznYMOoAfjmxvjmxvjm5tK4ut7H78kabBs8UtSw5j4JalhTPwzEBEXRMSnI+LBiHggIt7WYZtXR8RXImJf+fPrfY7xsYj4Qnns8Q7rIyL+oCyMtz8iLu1jbC9tOS/7IuKrEfH2tm36ev4i4kMRcSgi7m9Zdm5E3BERD5ePK7rsu7Xc5uGI2NrH+H4nIh4q//1ujYjlXfad9rNQYXzviognWv4Nr+yyb+VFGrvEd3NLbI9FxL4u+/bj/HXMKX37DGamPz1+gDXApeXzZRTzEF7Wts2rgU8OMMbHgFXTrL8S+GuKmdOvBO4ZUJxnAf8KfNsgzx/wKuBS4P6WZTcC15fPrwdu6LDfucCXyscV5fMVfYrvtcCi8vkNneKbyWehwvjeBfz3Gfz7Pwq8BDgbuK/9b6mq+NrW/y7w6wM8fx1zSr8+g7b4ZyAzD2bmveXz54AH6VBfqOauAj6chc8CyyNizQDiuBx4NDMHOhM7Mz8DPNO2+CpgV/l8F/D6Drv+MHBHZj6TmUeBO4Ar+hFfZt6emSfLl5+lmPU+EF3O30z0pUjjdPFFRABvBD4238edqWlySl8+gyb+WYqIDcB3A/d0WP19EXFfRPx1RLy8r4EV9Y5uj4i9EbGtw/oZFcfrg2vo/gc3yPMHcH5mHoTiDxM4r8M2dTmPP0fxDa6TXp+FKr217Ir6UJduijqcv+8HnsrMh7us7+v5a8spffkMmvhnISKWAruBt2fmV9tW30vRfXEJ8IfAX/Y5vM2ZeSnFfQ5+OSJe1bZ+RsXxqhQRZwNbgL/osHrQ52+m6nAe3wmcBD7SZZNen4WqvB/4dmATcJCiO6XdwM8fcC3Tt/b7dv565JSuu3VYNqtzaOKfoYgYpfgH+khmfqJ9fWZ+NTOPlc8/BYxGxKp+xZeZT5aPh4BbKb5St5p1cbwK/Ahwb2Y+1b5i0Oev9NRU91f5eKjDNgM9j+WFvNcBb86yw7fdDD4LlcjMpzLz65k5Cfxpl+MO+vwtAn4CuLnbNv06f11ySl8+gyb+GSj7BD8IPJiZ7+2yzbeW2xERr6A4t0f6FN+LImLZ1HOKi4D3t212G/BfytE9rwS+MvWVso+6trQGef5a3AZMjZDYCuzpsM3fAK+NiBVlV8Zry2WVi4grgB3Alsz8ty7bzOSzUFV8rdeMfrzLcT8PXBQRF5bfAK+hOO/98kPAQ5l5oNPKfp2/aXJKfz6DVV65HpYf4D9TfJXaD+wrf64Efgn4pXKbtwIPUIxS+Czwn/oY30vK495XxvDOcnlrfEFxy8tHgS8AY30+h99Ekci/pWXZwM4fxX9AB4ETFC2o64CVwJ3Aw+XjueW2Y8AHWvb9OeCR8udn+xjfIxR9u1OfwT8ut30x8KnpPgt9iu/Py8/WfooEtqY9vvL1lRSjWB7tZ3zl8j+b+sy1bDuI89ctp/TlM2jJBklqGLt6JKlhTPyS1DAmfklqGBO/JDWMiV+SGsbEL7WIiHeW1RL3l9UZv7dcvjoiTkTEL7Zt/1hE/F3bsn1tVSF/taxE+c8R8cP9+U2k7gZyz12pjiLi+yhmxV6amRPlzOGzy9VvoJhfcC3wJ227LouICzLz8Yj4rrb3fBnFJKWXU4wX/z8R8R2Z+fUqfxdpOrb4pVPWAE9n5gRAZj6d5fR9ioT/DmBdRLQXxLoF+KmW7VpnJ18F3JSZE5n5LxQTbvpSQkHqxsQvnXI7cEFEfDEi/igifgCKm2YA35qZn+P0JD/l4xT1XwB+DPirlnV1qEYpncbEL5WyKBL3PcA24DBwc0S8haKr5pZys5soWvWtngGORsQ1FHXVW+vo1KEapXQa+/ilFmXf+93A3RHxBYpCWWuB8yPizeVmL46Ii/L0eu43U9RCekvbW9ahKqp0Glv8UimKewNf1LJoE0Xj6EWZuTYzN2TmBuDdFN8CWt1Kcdu89iqJtwHXRMTiiLgQuAj4XCW/gDRDtvilU5YCfxjFTcxPUlyIfZSiUmOr3RRdPv9zakEWt8+7AaCsLj21/IGIuAX4p/I9f9kRPRo0q3NKUsPY1SNJDWPil6SGMfFLUsOY+CWpYUz8ktQwJn5JahgTvyQ1zL8DJGoXf2HL/Z8AAAAASUVORK5CYII=\n",
+ "image/png": "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\n",
"text/plain": [
""
]
@@ -662,18 +696,22 @@
{
"data": {
"text/plain": [
- "{'id': 'local/ff16115bd3c7163a6e8e',\n",
- " 'type': 'debug',\n",
- " 'content': {'name': 'example 2',\n",
+ "{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'type': 'Document',\n",
+ " 'content': {'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
" 'description': 'I really need to write a better description for my data.',\n",
" 'author': 'Tim'},\n",
" 'acl': {'readers': ['public']},\n",
- " 'metadata': {'createdOn': 1612797369664,\n",
- " 'createdBy': 'local/bc51a83eea09846dc024',\n",
- " 'modifiedOn': 1612797370136,\n",
- " 'modifiedBy': 'local/bc51a83eea09846dc024',\n",
- " 'txnId': 1612797369664041},\n",
- " 'payloads': [{'name': 'p1', 'filename': 'example-data.csv', 'size': 385}]}"
+ " 'metadata': {'createdOn': 1652894196042,\n",
+ " 'createdBy': 'admin',\n",
+ " 'modifiedOn': 1652894196352,\n",
+ " 'modifiedBy': 'admin',\n",
+ " 'txnId': 1652894196042028},\n",
+ " 'payloads': [{'name': 'p1',\n",
+ " 'filename': 'example-data.csv',\n",
+ " 'mediaType': 'application/octet-stream',\n",
+ " 'size': 385}]}"
]
},
"execution_count": 17,
@@ -711,16 +749,20 @@
{
"data": {
"text/plain": [
- "{'id': 'local/ff16115bd3c7163a6e8e',\n",
- " 'type': 'debug',\n",
- " 'content': {'SAM1': 'Level of CXCR4 expression'},\n",
+ "{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'type': 'Document',\n",
+ " 'content': {'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'SAM1': 'Level of CXCR4 expression'},\n",
" 'acl': {'readers': ['public']},\n",
- " 'metadata': {'createdOn': 1612797369664,\n",
- " 'createdBy': 'local/bc51a83eea09846dc024',\n",
- " 'modifiedOn': 1612797370153,\n",
- " 'modifiedBy': 'local/bc51a83eea09846dc024',\n",
- " 'txnId': 1612797369664041},\n",
- " 'payloads': [{'name': 'p1', 'filename': 'example-data.csv', 'size': 385}]}"
+ " 'metadata': {'createdOn': 1652894196042,\n",
+ " 'createdBy': 'admin',\n",
+ " 'modifiedOn': 1652894196364,\n",
+ " 'modifiedBy': 'admin',\n",
+ " 'txnId': 1652894196042028},\n",
+ " 'payloads': [{'name': 'p1',\n",
+ " 'filename': 'example-data.csv',\n",
+ " 'mediaType': 'application/octet-stream',\n",
+ " 'size': 385}]}"
]
},
"execution_count": 18,
@@ -785,8 +827,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "\n",
- "401 Client Error: Unauthorized for url: https://127.0.0.1/objects/local/ff16115bd3c7163a6e8e?full=True\n"
+ "{'message': 'Unauthenticated'}\n",
+ "401 Client Error: Unauthorized for url: https://127.0.0.1:8443/objects/test/d92d43a269b89a3e6a10?full=True\n"
]
}
],
@@ -807,18 +849,22 @@
{
"data": {
"text/plain": [
- "{'id': 'local/ff16115bd3c7163a6e8e',\n",
- " 'type': 'debug',\n",
- " 'content': {'name': 'example 2',\n",
+ "{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'type': 'Document',\n",
+ " 'content': {'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
" 'description': 'another example of metadata for CSV payload',\n",
" 'author': 'Tim'},\n",
" 'acl': {},\n",
- " 'metadata': {'createdOn': 1612797369664,\n",
- " 'createdBy': 'local/bc51a83eea09846dc024',\n",
- " 'modifiedOn': 1612797370197,\n",
- " 'modifiedBy': 'local/bc51a83eea09846dc024',\n",
- " 'txnId': 1612797370170042},\n",
- " 'payloads': [{'name': 'p1', 'filename': 'example-data.csv', 'size': 385}]}"
+ " 'metadata': {'createdOn': 1652894196042,\n",
+ " 'createdBy': 'admin',\n",
+ " 'modifiedOn': 1652894196383,\n",
+ " 'modifiedBy': 'admin',\n",
+ " 'txnId': 1652894196378029},\n",
+ " 'payloads': [{'name': 'p1',\n",
+ " 'filename': 'example-data.csv',\n",
+ " 'mediaType': 'application/octet-stream',\n",
+ " 'size': 385}]}"
]
},
"execution_count": 21,
diff --git a/examples/examples.ipynb b/examples/examples.ipynb
index 7452f32..5c8e97a 100644
--- a/examples/examples.ipynb
+++ b/examples/examples.ipynb
@@ -4,12 +4,23 @@
"cell_type": "code",
"execution_count": 1,
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/home/sven/7/Work/ThesisMatData/CordraPy/cordra/cordra.py:67: UserWarning: CordraObject may be moved to a new module with a new name in future releases.\n",
+ " warn(\"CordraObject may be moved to a new module with a new name in future releases.\")\n",
+ "/home/sven/7/Work/ThesisMatData/CordraPy/cordra/cordra.py:376: UserWarning: Token may be moved to a new module with a new name in future releases.\n",
+ " warn(\"Token may be moved to a new module with a new name in future releases.\")\n"
+ ]
+ }
+ ],
"source": [
"import getpass\n",
"import cordra\n",
"from lucenequerybuilder import Q\n",
- "from io import StringIO\n",
+ "from io import StringIO, BytesIO\n",
"import pandas as pd\n",
"import matplotlib.pyplot as plt"
]
@@ -27,8 +38,8 @@
"metadata": {},
"outputs": [],
"source": [
- "host = \"https://localhost\"\n",
- "obj_type = \"debug\""
+ "host = \"https://127.0.0.1:8443\"\n",
+ "obj_type = \"Document\""
]
},
{
@@ -52,7 +63,7 @@
}
],
"source": [
- "username = \"testuser1\"\n",
+ "username = \"admin\"\n",
"password = getpass.getpass()"
]
},
@@ -71,7 +82,8 @@
{
"data": {
"text/plain": [
- "{'name': 'example 1',\n",
+ "{'id': 'test/f1f0188d7e74ce2e9b39',\n",
+ " 'name': 'example 1',\n",
" 'description': 'an example of metadata for CSV payload',\n",
" 'author': 'John'}"
]
@@ -113,7 +125,8 @@
{
"data": {
"text/plain": [
- "{'name': 'example 2',\n",
+ "{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
" 'description': 'another example of metadata for CSV payload',\n",
" 'author': 'Tim'}"
]
@@ -172,10 +185,12 @@
"{'pageNum': 0,\n",
" 'pageSize': -1,\n",
" 'size': 2,\n",
- " 'results': [{'name': 'example 1',\n",
+ " 'results': [{'id': 'test/f1f0188d7e74ce2e9b39',\n",
+ " 'name': 'example 1',\n",
" 'description': 'an example of metadata for CSV payload',\n",
" 'author': 'John'},\n",
- " {'name': 'example 2',\n",
+ " {'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
" 'description': 'another example of metadata for CSV payload',\n",
" 'author': 'Tim'}]}"
]
@@ -209,18 +224,22 @@
"{'pageNum': 0,\n",
" 'pageSize': -1,\n",
" 'size': 1,\n",
- " 'results': [{'id': 'local/891476bbf9a80dae850c',\n",
- " 'type': 'debug',\n",
- " 'content': {'name': 'example 1',\n",
+ " 'results': [{'id': 'test/f1f0188d7e74ce2e9b39',\n",
+ " 'type': 'Document',\n",
+ " 'content': {'id': 'test/f1f0188d7e74ce2e9b39',\n",
+ " 'name': 'example 1',\n",
" 'description': 'an example of metadata for CSV payload',\n",
" 'author': 'John'},\n",
" 'acl': {'readers': ['public']},\n",
- " 'metadata': {'createdOn': 1612797334222,\n",
- " 'createdBy': 'local/bc51a83eea09846dc024',\n",
- " 'modifiedOn': 1612797334222,\n",
- " 'modifiedBy': 'local/bc51a83eea09846dc024',\n",
- " 'txnId': 1612797334222035},\n",
- " 'payloads': [{'name': 'p1', 'filename': 'example-data.csv', 'size': 385}]}]}"
+ " 'metadata': {'createdOn': 1652912293301,\n",
+ " 'createdBy': 'admin',\n",
+ " 'modifiedOn': 1652912293301,\n",
+ " 'modifiedBy': 'admin',\n",
+ " 'txnId': 1652912293301944},\n",
+ " 'payloads': [{'name': 'p1',\n",
+ " 'filename': 'example-data.csv',\n",
+ " 'mediaType': 'application/octet-stream',\n",
+ " 'size': 385}]}]}"
]
},
"execution_count": 7,
@@ -246,18 +265,22 @@
"{'pageNum': 0,\n",
" 'pageSize': -1,\n",
" 'size': 1,\n",
- " 'results': [{'id': 'local/9c53077e1b8e609d087c',\n",
- " 'type': 'debug',\n",
- " 'content': {'name': 'example 2',\n",
+ " 'results': [{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'type': 'Document',\n",
+ " 'content': {'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
" 'description': 'another example of metadata for CSV payload',\n",
" 'author': 'Tim'},\n",
" 'acl': {'readers': ['public']},\n",
- " 'metadata': {'createdOn': 1612797334352,\n",
- " 'createdBy': 'local/bc51a83eea09846dc024',\n",
- " 'modifiedOn': 1612797334352,\n",
- " 'modifiedBy': 'local/bc51a83eea09846dc024',\n",
- " 'txnId': 1612797334352036},\n",
- " 'payloads': [{'name': 'p1', 'filename': 'example-data.csv', 'size': 385}]}]}"
+ " 'metadata': {'createdOn': 1652912293368,\n",
+ " 'createdBy': 'admin',\n",
+ " 'modifiedOn': 1652912293368,\n",
+ " 'modifiedBy': 'admin',\n",
+ " 'txnId': 1652912293368945},\n",
+ " 'payloads': [{'name': 'p1',\n",
+ " 'filename': 'example-data.csv',\n",
+ " 'mediaType': 'application/octet-stream',\n",
+ " 'size': 385}]}]}"
]
},
"execution_count": 8,
@@ -287,7 +310,7 @@
{
"data": {
"text/plain": [
- "'local/9c53077e1b8e609d087c'"
+ "'test/d92d43a269b89a3e6a10'"
]
},
"execution_count": 9,
@@ -307,7 +330,8 @@
{
"data": {
"text/plain": [
- "{'name': 'example 2',\n",
+ "{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
" 'description': 'another example of metadata for CSV payload',\n",
" 'author': 'Tim'}"
]
@@ -330,18 +354,22 @@
{
"data": {
"text/plain": [
- "{'id': 'local/9c53077e1b8e609d087c',\n",
- " 'type': 'debug',\n",
- " 'content': {'name': 'example 2',\n",
+ "{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'type': 'Document',\n",
+ " 'content': {'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
" 'description': 'another example of metadata for CSV payload',\n",
" 'author': 'Tim'},\n",
" 'acl': {'readers': ['public']},\n",
- " 'metadata': {'createdOn': 1612797334352,\n",
- " 'createdBy': 'local/bc51a83eea09846dc024',\n",
- " 'modifiedOn': 1612797334352,\n",
- " 'modifiedBy': 'local/bc51a83eea09846dc024',\n",
- " 'txnId': 1612797334352036},\n",
- " 'payloads': [{'name': 'p1', 'filename': 'example-data.csv', 'size': 385}]}"
+ " 'metadata': {'createdOn': 1652912293368,\n",
+ " 'createdBy': 'admin',\n",
+ " 'modifiedOn': 1652912293368,\n",
+ " 'modifiedBy': 'admin',\n",
+ " 'txnId': 1652912293368945},\n",
+ " 'payloads': [{'name': 'p1',\n",
+ " 'filename': 'example-data.csv',\n",
+ " 'mediaType': 'application/octet-stream',\n",
+ " 'size': 385}]}"
]
},
"execution_count": 11,
@@ -383,7 +411,7 @@
{
"data": {
"text/plain": [
- "'\\ufeff\"SAM0\",\"SAM1\"\\r\\n1.00,2.302389071\\r\\n2.00,3.71503899\\r\\n3.00,9.426125622\\r\\n4.00,11.34529125\\r\\n5.00,11.87704484\\r\\n6.00,19.01325695\\r\\n7.00,21.52353652\\r\\n8.00,28.28670056\\r\\n9.00,29.55737761\\r\\n10.00,25.89582707\\r\\n11.00,31.57982065\\r\\n12.00,36.02452105\\r\\n13.00,39.47686412\\r\\n14.00,44.41192202\\r\\n15.00,43.36098819\\r\\n16.00,48.61525381\\r\\n17.00,53.91222295\\r\\n18.00,54.28420278\\r\\n19.00,53.1378195\\r\\n20.00,55.88015939'"
+ "b'\\xef\\xbb\\xbf\"SAM0\",\"SAM1\"\\r\\n1.00,2.302389071\\r\\n2.00,3.71503899\\r\\n3.00,9.426125622\\r\\n4.00,11.34529125\\r\\n5.00,11.87704484\\r\\n6.00,19.01325695\\r\\n7.00,21.52353652\\r\\n8.00,28.28670056\\r\\n9.00,29.55737761\\r\\n10.00,25.89582707\\r\\n11.00,31.57982065\\r\\n12.00,36.02452105\\r\\n13.00,39.47686412\\r\\n14.00,44.41192202\\r\\n15.00,43.36098819\\r\\n16.00,48.61525381\\r\\n17.00,53.91222295\\r\\n18.00,54.28420278\\r\\n19.00,53.1378195\\r\\n20.00,55.88015939'"
]
},
"execution_count": 13,
@@ -428,102 +456,102 @@
" \n",
" \n",
" \n",
- " 0 | \n",
+ " 0 | \n",
" 1.0 | \n",
" 2.302389 | \n",
"
\n",
" \n",
- " 1 | \n",
+ " 1 | \n",
" 2.0 | \n",
" 3.715039 | \n",
"
\n",
" \n",
- " 2 | \n",
+ " 2 | \n",
" 3.0 | \n",
" 9.426126 | \n",
"
\n",
" \n",
- " 3 | \n",
+ " 3 | \n",
" 4.0 | \n",
" 11.345291 | \n",
"
\n",
" \n",
- " 4 | \n",
+ " 4 | \n",
" 5.0 | \n",
" 11.877045 | \n",
"
\n",
" \n",
- " 5 | \n",
+ " 5 | \n",
" 6.0 | \n",
" 19.013257 | \n",
"
\n",
" \n",
- " 6 | \n",
+ " 6 | \n",
" 7.0 | \n",
" 21.523537 | \n",
"
\n",
" \n",
- " 7 | \n",
+ " 7 | \n",
" 8.0 | \n",
" 28.286701 | \n",
"
\n",
" \n",
- " 8 | \n",
+ " 8 | \n",
" 9.0 | \n",
" 29.557378 | \n",
"
\n",
" \n",
- " 9 | \n",
+ " 9 | \n",
" 10.0 | \n",
" 25.895827 | \n",
"
\n",
" \n",
- " 10 | \n",
+ " 10 | \n",
" 11.0 | \n",
" 31.579821 | \n",
"
\n",
" \n",
- " 11 | \n",
+ " 11 | \n",
" 12.0 | \n",
" 36.024521 | \n",
"
\n",
" \n",
- " 12 | \n",
+ " 12 | \n",
" 13.0 | \n",
" 39.476864 | \n",
"
\n",
" \n",
- " 13 | \n",
+ " 13 | \n",
" 14.0 | \n",
" 44.411922 | \n",
"
\n",
" \n",
- " 14 | \n",
+ " 14 | \n",
" 15.0 | \n",
" 43.360988 | \n",
"
\n",
" \n",
- " 15 | \n",
+ " 15 | \n",
" 16.0 | \n",
" 48.615254 | \n",
"
\n",
" \n",
- " 16 | \n",
+ " 16 | \n",
" 17.0 | \n",
" 53.912223 | \n",
"
\n",
" \n",
- " 17 | \n",
+ " 17 | \n",
" 18.0 | \n",
" 54.284203 | \n",
"
\n",
" \n",
- " 18 | \n",
+ " 18 | \n",
" 19.0 | \n",
" 53.137819 | \n",
"
\n",
" \n",
- " 19 | \n",
+ " 19 | \n",
" 20.0 | \n",
" 55.880159 | \n",
"
\n",
@@ -561,7 +589,7 @@
}
],
"source": [
- "df = pd.read_csv(StringIO(payload))\n",
+ "df = pd.read_csv(BytesIO(payload))\n",
"df"
]
},
@@ -572,7 +600,7 @@
"outputs": [
{
"data": {
- "image/png": "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\n",
+ "image/png": "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\n",
"text/plain": [
""
]
@@ -614,18 +642,22 @@
{
"data": {
"text/plain": [
- "{'id': 'local/9c53077e1b8e609d087c',\n",
- " 'type': 'debug',\n",
- " 'content': {'name': 'example 2',\n",
+ "{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'type': 'Document',\n",
+ " 'content': {'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
" 'description': 'I really need to write a better description for my data.',\n",
" 'author': 'Tim'},\n",
" 'acl': {'readers': ['public']},\n",
- " 'metadata': {'createdOn': 1612797334352,\n",
- " 'createdBy': 'local/bc51a83eea09846dc024',\n",
- " 'modifiedOn': 1612797334802,\n",
- " 'modifiedBy': 'local/bc51a83eea09846dc024',\n",
- " 'txnId': 1612797334352036},\n",
- " 'payloads': [{'name': 'p1', 'filename': 'example-data.csv', 'size': 385}]}"
+ " 'metadata': {'createdOn': 1652912293368,\n",
+ " 'createdBy': 'admin',\n",
+ " 'modifiedOn': 1652912293670,\n",
+ " 'modifiedBy': 'admin',\n",
+ " 'txnId': 1652912293368945},\n",
+ " 'payloads': [{'name': 'p1',\n",
+ " 'filename': 'example-data.csv',\n",
+ " 'mediaType': 'application/octet-stream',\n",
+ " 'size': 385}]}"
]
},
"execution_count": 16,
@@ -664,16 +696,20 @@
{
"data": {
"text/plain": [
- "{'id': 'local/9c53077e1b8e609d087c',\n",
- " 'type': 'debug',\n",
- " 'content': {'SAM1': 'Level of CXCR4 expression'},\n",
+ "{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'type': 'Document',\n",
+ " 'content': {'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'SAM1': 'Level of CXCR4 expression'},\n",
" 'acl': {'readers': ['public']},\n",
- " 'metadata': {'createdOn': 1612797334352,\n",
- " 'createdBy': 'local/bc51a83eea09846dc024',\n",
- " 'modifiedOn': 1612797334842,\n",
- " 'modifiedBy': 'local/bc51a83eea09846dc024',\n",
- " 'txnId': 1612797334352036},\n",
- " 'payloads': [{'name': 'p1', 'filename': 'example-data.csv', 'size': 385}]}"
+ " 'metadata': {'createdOn': 1652912293368,\n",
+ " 'createdBy': 'admin',\n",
+ " 'modifiedOn': 1652912293704,\n",
+ " 'modifiedBy': 'admin',\n",
+ " 'txnId': 1652912293368945},\n",
+ " 'payloads': [{'name': 'p1',\n",
+ " 'filename': 'example-data.csv',\n",
+ " 'mediaType': 'application/octet-stream',\n",
+ " 'size': 385}]}"
]
},
"execution_count": 17,
@@ -740,8 +776,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "\n",
- "401 Client Error: Unauthorized for url: https://localhost/objects/local/9c53077e1b8e609d087c?full=True\n"
+ "{'message': 'Unauthenticated'}\n",
+ "401 Client Error: Unauthorized for url: https://127.0.0.1:8443/objects/test/d92d43a269b89a3e6a10?full=True\n"
]
}
],
@@ -762,18 +798,22 @@
{
"data": {
"text/plain": [
- "{'id': 'local/9c53077e1b8e609d087c',\n",
- " 'type': 'debug',\n",
- " 'content': {'name': 'example 2',\n",
+ "{'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'type': 'Document',\n",
+ " 'content': {'id': 'test/d92d43a269b89a3e6a10',\n",
+ " 'name': 'example 2',\n",
" 'description': 'another example of metadata for CSV payload',\n",
" 'author': 'Tim'},\n",
" 'acl': {},\n",
- " 'metadata': {'createdOn': 1612797334352,\n",
- " 'createdBy': 'local/bc51a83eea09846dc024',\n",
- " 'modifiedOn': 1612797334920,\n",
- " 'modifiedBy': 'local/bc51a83eea09846dc024',\n",
- " 'txnId': 1612797334892037},\n",
- " 'payloads': [{'name': 'p1', 'filename': 'example-data.csv', 'size': 385}]}"
+ " 'metadata': {'createdOn': 1652912293368,\n",
+ " 'createdBy': 'admin',\n",
+ " 'modifiedOn': 1652912293743,\n",
+ " 'modifiedBy': 'admin',\n",
+ " 'txnId': 1652912293738946},\n",
+ " 'payloads': [{'name': 'p1',\n",
+ " 'filename': 'example-data.csv',\n",
+ " 'mediaType': 'application/octet-stream',\n",
+ " 'size': 385}]}"
]
},
"execution_count": 20,
@@ -798,6 +838,13 @@
"execution_count": 21,
"metadata": {},
"outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{}\n"
+ ]
+ },
{
"data": {
"text/plain": [
@@ -819,6 +866,13 @@
"execution_count": 22,
"metadata": {},
"outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{}\n"
+ ]
+ },
{
"data": {
"text/plain": [
@@ -835,12 +889,57 @@
"response"
]
},
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Delete parts of objects"
+ ]
+ },
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 23,
"metadata": {},
- "outputs": [],
- "source": []
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{'id': 'test/90c5eb8ac8911ec5f400', 'name': 'hello', 'otherName': 'bye'}\n",
+ "https://localhost:8443/objects/test/90c5eb8ac8911ec5f400\n",
+ "\n",
+ "{'id': 'test/90c5eb8ac8911ec5f400', 'name': 'hello', 'otherName': 'bye'}\n"
+ ]
+ }
+ ],
+ "source": [
+ "from cordra.cordra import set_auth\n",
+ "import requests\n",
+ "import json\n",
+ "\n",
+ "r = requests.post(\"https://localhost:8443/objects/\", params={\"type\": \"Document\"}, json={\"name\": \"hello\", \"otherName\": \"bye\"},\n",
+ " auth=set_auth(username,password), verify=False)\n",
+ "\n",
+ "print(r.json())\n",
+ "\n",
+ "id1 = r.json()[\"id\"]\n",
+ "\n",
+ "url = f\"https://localhost:8443/objects/{id1}\"\n",
+ "print(url)\n",
+ "\n",
+ "r = requests.delete(url, params={\"jsonPointer\": \"/otherName\"},\n",
+ " auth=set_auth(username,password),verify=False)\n",
+ "\n",
+ "print(r)\n",
+ "\n",
+ "print(requests.get(url, auth=set_auth(username,password),verify=False).json())\n",
+ "\n",
+ "# r = requests.put(url, params={\"jsonPointer\": \"/otherName\"}, data='null',\n",
+ "# auth=set_auth(username,password),verify=False)\n",
+ "\n",
+ "# print(r)\n",
+ "# print(requests.get(url, auth=set_auth(username,password),verify=False).json())"
+ ]
}
],
"metadata": {
diff --git a/tests/CRUD_CordraClient.py b/tests/CRUD_CordraClient.py
new file mode 100644
index 0000000..9068bf8
--- /dev/null
+++ b/tests/CRUD_CordraClient.py
@@ -0,0 +1,347 @@
+"""Check the CordraClient Class and its functionality. Should be able to fully reproduce the
+functionality of the Cordra REST API. This includes the following tests:
+* Authorize using user / password
+* Authorize using a secret key
+* Maintain a token for subsequent authorization
+* Delete an authorization token
+* Create a cordra object and read back an identical object
+* Create a cordra object with a json payload and read back an identical json object
+* Create a cordra object with a csv payload and read back an identical csv object
+* Create a cordra object with an image payload and read back an identical image
+* Update a cordra object and read back an object with the changes
+* Update a json payload and read back an identical json object
+* Update a csv payload and read back an identical csv object
+* Update an image payload and read back an identical image
+* Set the ACL on a cordra object on create and verify only specified readers have access
+* Update the ACL of a cordra object and verify only current specified readers have access
+* Delete a cordra object with a user and verify it doesn't exist with admin
+* Delete a cordra object attribute and read the object to verify deletion
+* Delete a cordra object payload and read the object to verify deletion
+* Query cordra for all created objects and delete them
+"""
+
+# from cordra import CordraObject
+from cordra import CordraClient, CordraObject
+from io import BytesIO
+from PIL import Image
+import os
+import json
+import requests
+import copy
+
+
+# ---------------- #
+# Helper Functions #
+# ---------------- #
+def auth_wrapper(func):
+ '''Reusability of the auth code'''
+ def inner():
+ client = CordraClient(
+ host="https://localhost:8443/",
+ username="admin", password="admin",
+ verify=False
+ )
+ func(client)
+ client.delete_auth()
+
+ return inner
+
+
+def acl_wrapper(func):
+ '''Generating clients for admin and two users.'''
+ def inner():
+ client = CordraClient(
+ host="https://localhost:8443/",
+ username="admin", password="admin",
+ verify=False
+ )
+
+ client_user1 = CordraClient(
+ host="https://localhost:8443/",
+ username="user1", password="user.1234",
+ verify=False
+ )
+
+ client_user2 = CordraClient(
+ host="https://localhost:8443/",
+ username="user2", password="user.1234",
+ verify=False
+ )
+
+ user1_id = client.find('/username:"user1"')["results"][0]["id"]
+ user2_id = client.find('/username:"user2"')["results"][0]["id"]
+
+ func(client, user1_id, client_user1, user2_id, client_user2)
+ client.delete_auth()
+ client_user1.delete_auth()
+ client_user2.delete_auth()
+
+ return inner
+
+
+# ----- #
+# Setup #
+# ----- #
+
+@auth_wrapper
+def setup(client_admin):
+ '''Creating users with the admin account'''
+
+ client_admin.create({"username": "user1", "password": "user.1234"}, "User")
+ client_admin.create({"username": "user2", "password": "user.1234"}, "User")
+
+
+@auth_wrapper
+def teardown(client_admin):
+ '''Deleting all objects and users with the admin account. Excludes schemas.
+ Query cordra for all created objects and delete them.'''
+
+ r = client_admin.find("*", pageSize=-1, full=True)
+ all_objectIds = [ri['id'] for ri in r['results'] if ri['type']!='Schema']
+
+ for obj_id in all_objectIds:
+ client_admin.delete(obj_id)
+
+
+# ----- #
+# Tests #
+# ----- #
+tests = []
+
+@auth_wrapper
+def test(client):
+ '''Authorize using user / password.
+ Maintain a token for subsequent authorization.
+ Delete an authorization token.'''
+
+ client.check_auth()
+
+tests.append(test)
+
+
+def test():
+ '''Authorize using a secret key'''
+ #TODO: implement secret key in cordraClient then write this test
+ pass
+
+tests.append(test)
+
+
+@auth_wrapper
+def test(client):
+ '''Create a cordra object and read back an identical object.
+ Update a cordra object and read back an object with the changes.'''
+
+ # Create object
+ obj1 = {"@type": "Document", "name": "test1"}
+ r = client.create(obj1, "Document")
+ obj1_id = r["id"]
+ obj1["id"] = obj1_id
+ assert obj1 == r
+
+ obj1_clone = client.read(obj1_id)
+ assert obj1 == obj1_clone
+
+ # Update object
+ obj1.update({"name": "test1-update"})
+ r = client.update(obj1, obj1_id)
+ assert obj1 == r
+
+ obj1_clone = client.read(obj1_id)
+ assert obj1 == obj1_clone
+
+tests.append(test)
+
+
+
+@auth_wrapper
+def test(client):
+ '''Create a cordra object with a json payload and read back an identical json object.
+ Update a json payload and read back an identical json object.'''
+
+ obj1 = {"@type": "Document", "name": "test1"}
+ pay1 = {"some_info": 123}
+
+ # Create the obj and pay by encoding payload into bytes object
+ r = client.create(obj1, "Document", payloads={"json": json.dumps(pay1)})
+ obj1_id = r["id"]
+ obj1["id"] = obj1_id
+ assert obj1 == r
+
+ obj1_clone, pay1_clone = client.read(obj1_id, getObjPayTuple=True)
+ assert obj1 == obj1_clone
+ assert pay1 == pay1_clone["json"]
+
+ # Update the payload
+ pay1 = {"other_info": 456}
+ r = client.update(obj1, obj1_id, payloads={"json": json.dumps(pay1)})
+
+ obj1_clone, pay1_clone = client.read(obj1_id, getObjPayTuple=True)
+ assert obj1 == obj1_clone
+ assert pay1 == pay1_clone["json"]
+
+tests.append(test)
+
+
+@auth_wrapper
+def test(client):
+ '''Create a cordra object with a csv payload and read back an identical csv object.
+ Update a csv payload and read back an identical csv object.'''
+
+ # Create csv
+ csv = ""
+ for i in range(10):
+ csv += f"{2*i},{2*i+1}\n"
+
+ csv = csv.encode()
+
+ # Write csv to cordra
+ obj1 = {"@type": "Document", "name": "test1"}
+ r = client.create(obj1, "Document", payloads={"csv": csv})
+ obj1_id = r["id"]
+ obj1["id"] = obj1_id
+ assert obj1 == r
+
+ obj1_clone, pay1_clone = client.read(obj1_id, getObjPayTuple=True)
+ assert obj1 == obj1_clone
+ assert csv == pay1_clone["csv"]
+
+ # Update csv in cordra
+ csv = "\n".join(csv.decode("utf-8").split("\n")[:5]).encode()
+ client.update(obj1, obj1_id, payloads={"csv": csv})
+
+ obj1_clone, pay1_clone = client.read(obj1_id, getObjPayTuple=True)
+ assert obj1 == obj1_clone
+ assert csv == pay1_clone["csv"]
+
+tests.append(test)
+
+
+@auth_wrapper
+def test(client):
+ '''Create a cordra object with an image payload and read back an identical image.
+ Update an image payload and read back an identical image.'''
+
+ # Create image
+ stream = BytesIO()
+ A = Image.radial_gradient("L").resize((11,11))
+ A.save(stream, format="PNG") # Write a png image to bytes object
+ image = stream.getvalue()
+
+ # Write image to cordra
+ obj1 = {"@type": "Document", "name": "test1"}
+ r = client.create(obj1, "Document", payloads={"image": image})
+ obj1_id = r["id"]
+ obj1["id"] = obj1_id
+ assert obj1 == r
+
+ obj1_clone, pay1_clone = client.read(obj1_id, getObjPayTuple=True)
+ assert obj1 == obj1_clone
+ assert image == pay1_clone["image"]
+
+ # Update image
+ stream = BytesIO()
+ A = A.resize((9,9))
+ A.save(stream, format="PNG") # Write a png image to bytes object
+ image = stream.getvalue()
+
+ r = client.update(obj1, obj1_id, payloads={"image": image})
+
+ obj1_clone, pay1_clone = client.read(obj1_id, getObjPayTuple=True)
+ assert obj1 == obj1_clone
+ assert image == pay1_clone["image"]
+
+tests.append(test)
+
+
+@acl_wrapper
+def test(client, user1_id, client_user1, user2_id, client_user2):
+ '''Set the ACL on a cordra object on create and verify only specified readers have access.
+ Update the ACL of a cordra object and verify only current specified readers have access.'''
+
+ # Create object and only allow user1 access
+ r = client.create(
+ {"name": "unaccessible"},
+ "Document",
+ acls={"readers":[user1_id],"writers":None}
+ )
+ obj_id = r[0]['id']
+
+ client_user1.read(obj_id)
+
+ # this should return a 403 error
+ try:
+ client_user2.read(obj_id)
+ except Exception as e:
+ print("Successful error: ", e)
+
+ # Update access to user2
+ r = client.update(dict(), obj_id, acls={"readers":[user2_id],"writers":None})
+
+ client_user2.read(obj_id)
+
+ # this should return a 403 error
+ try:
+ client_user1.read(obj_id)
+ except Exception as e:
+ print("Successful error: ", e)
+
+tests.append(test)
+
+
+@acl_wrapper
+def test(client, user1_id, client_user1, user2_id, client_user2):
+ '''Delete a cordra object with a user and verify it doesn't exist with admin'''
+ r = client_user1.create({"deleteThis": True}, "Document")
+ obj_id = r["id"]
+ client_user1.delete(obj_id)
+
+ # should return a 404 not found error
+ try:
+ client.read(obj_id)
+ except Exception as e:
+ print("Successful error: ", e)
+
+tests.append(test)
+
+
+# @acl_wrapper
+# def test(client, user1_id, client_user1, user2_id, client_user2):
+# '''Delete a cordra object attribute and read the object to verify deletion'''
+# r = client_user1.create({"keepThis": True, "deleteThis": True}, "Document")
+# obj_id = r["id"]
+
+# print(client_user1.params["token"])
+# r = CordraObject.update(host="https://localhost:8443/", obj_id=obj_id, obj_json=None, jsonPointer="/deleteThis", token=client_user1.params["token"], verify=False)
+
+# print(r)
+
+
+# # r = CordraObject.delete(host="https://localhost:8443/", obj_id=obj_id, jsonPointer="deleteThis", token=client_user1.params["token"], verify=False)
+
+# # print(r)
+
+# obj = client.read(obj_id)
+# print(obj)
+
+# assert "keepThis" in obj
+# assert "deleteThis" not in obj
+
+# tests.append(test)
+
+
+# @acl_wrapper
+# def test(client, user1_id, client_user1, user2_id, client_user2):
+# '''Delete a cordra object payload and read the object to verify deletion'''
+
+# tests.append(test)
+
+
+
+if __name__ == "__main__":
+ try:
+ setup()
+ for test in tests:
+ test()
+ finally:
+ teardown()