From 2bee54f60dc0528945e529683989c429955600e5 Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Sat, 25 Feb 2023 13:09:37 -0700 Subject: [PATCH 01/23] [PTDT-1108] Added client method unarchive_root_schema_node --- labelbox/client.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/labelbox/client.py b/labelbox/client.py index 172184608..1546c9b3a 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -55,7 +55,8 @@ def __init__(self, api_key=None, endpoint='https://api.labelbox.com/graphql', enable_experimental=False, - app_url="https://app.labelbox.com"): + app_url="https://app.labelbox.com", + rest_endpoint="https://api.labelbox.com/api/v1"): """ Creates and initializes a Labelbox Client. Logging is defaulted to level WARNING. To receive more verbose @@ -95,6 +96,12 @@ def __init__(self, 'X-User-Agent': f'python-sdk {SDK_VERSION}' } self._data_row_metadata_ontology = None + self.rest_endpoint = rest_endpoint + self.rest_endpoint_headers = { + "authorization": "Bearer %s" % self.api_key, + 'X-User-Agent': 'python-sdk 0.0.0', + 'Content-Type': 'application/json', + } @retry.Retry(predicate=retry.if_exception_type( labelbox.exceptions.InternalServerError, @@ -1384,3 +1391,23 @@ def get_catalog_slice(self, slice_id) -> CatalogSlice: """ res = self.execute(query_str, {'id': slice_id}) return Entity.CatalogSlice(self, res['getSavedQuery']) + + def unarchive_root_feature_schema_node(self, ontology_id: str, root_feature_schema_id: str) -> bool: + """ + Returns true if the root feature schema node was successfully unarchived, false otherwise + Args: + root_feature_schema_id (str): The ID of the root level feature schema + ontology_id (str): The ID of the ontology + Returns: + bool + """ + ontology_endpoint = self.rest_endpoint + "/ontologies/" + ontology_id + '/root-feature-schemas/' + root_feature_schema_id + '/unarchive' + response = requests.patch( + ontology_endpoint, + headers=self.rest_endpoint_headers, + ) + if response.status_code == 200: + return response.json()['didUnarchive'] + else: + raise labelbox.exceptions.LabelboxError( + "Failed unarchive root feature schema node: ", response.text) From 4ff424207ec207ead7cf3382a7480fa250e95fcf Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Sat, 25 Feb 2023 13:15:10 -0700 Subject: [PATCH 02/23] Ran yapf formatter --- labelbox/client.py | 51 +++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/labelbox/client.py b/labelbox/client.py index 1546c9b3a..3be68990b 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -55,7 +55,7 @@ def __init__(self, api_key=None, endpoint='https://api.labelbox.com/graphql', enable_experimental=False, - app_url="https://app.labelbox.com", + app_url="https://app.labelbox.com", rest_endpoint="https://api.labelbox.com/api/v1"): """ Creates and initializes a Labelbox Client. @@ -156,7 +156,8 @@ def convert_value(value): if query is not None: if params is not None: params = { - key: convert_value(value) for key, value in params.items() + key: convert_value(value) + for key, value in params.items() } data = json.dumps({ 'query': query, @@ -357,18 +358,18 @@ def upload_data(self, request_data = { "operations": - json.dumps({ - "variables": { - "file": None, - "contentLength": len(content), - "sign": sign - }, - "query": - """mutation UploadFile($file: Upload!, $contentLength: Int!, + json.dumps({ + "variables": { + "file": None, + "contentLength": len(content), + "sign": sign + }, + "query": + """mutation UploadFile($file: Upload!, $contentLength: Int!, $sign: Boolean) { uploadFile(file: $file, contentLength: $contentLength, sign: $sign) {url filename} } """, - }), + }), "map": (None, json.dumps({"1": ["variables.file"]})), } response = requests.post( @@ -377,7 +378,7 @@ def upload_data(self, data=request_data, files={ "1": (filename, content, content_type) if - (filename and content_type) else content + (filename and content_type) else content }) if response.status_code == 502: @@ -665,7 +666,8 @@ def create_project(self, **kwargs) -> Project: elif queue_mode == QueueMode.Dataset: logger.warning( "QueueMode.Dataset will eventually be deprecated, and is no longer " - "recommended for new projects. Prefer QueueMode.Batch instead.") + "recommended for new projects. Prefer QueueMode.Batch instead." + ) return self._create(Entity.Project, { **kwargs, @@ -777,7 +779,7 @@ def get_data_row_ids_for_external_ids( for row in self.execute( query_str, {'externalId_in': external_ids[i:i + max_ids_per_request] - })['externalIdsToDataRowIds']: + })['externalIdsToDataRowIds']: result[row['externalId']].append(row['dataRowId']) return result @@ -1069,9 +1071,10 @@ def _format_failed_rows(rows: Dict[str, str], } """ params = { - 'globalKeyDataRowLinks': [{ - utils.camel_case(key): value for key, value in input.items() - } for input in global_key_to_data_row_inputs] + 'globalKeyDataRowLinks': + [{utils.camel_case(key): value + for key, value in input.items()} + for input in global_key_to_data_row_inputs] } assign_global_keys_to_data_rows_job = self.execute(query_str, params) @@ -1100,8 +1103,8 @@ def _format_failed_rows(rows: Dict[str, str], """ result_params = { "jobId": - assign_global_keys_to_data_rows_job["assignGlobalKeysToDataRows" - ]["jobId"] + assign_global_keys_to_data_rows_job["assignGlobalKeysToDataRows"] + ["jobId"] } # Poll job status until finished, then retrieve results @@ -1217,7 +1220,7 @@ def _format_failed_rows(rows: List[str], """ result_params = { "jobId": - data_rows_for_global_keys_job["dataRowsForGlobalKeys"]["jobId"] + data_rows_for_global_keys_job["dataRowsForGlobalKeys"]["jobId"] } # Poll job status until finished, then retrieve results @@ -1339,7 +1342,8 @@ def _format_failed_rows(rows: List[str], errors.extend( _format_failed_rows( data['notFoundGlobalKeys'], - "Failed to find data row matching provided global key")) + "Failed to find data row matching provided global key") + ) errors.extend( _format_failed_rows( data['accessDeniedGlobalKeys'], @@ -1391,8 +1395,9 @@ def get_catalog_slice(self, slice_id) -> CatalogSlice: """ res = self.execute(query_str, {'id': slice_id}) return Entity.CatalogSlice(self, res['getSavedQuery']) - - def unarchive_root_feature_schema_node(self, ontology_id: str, root_feature_schema_id: str) -> bool: + + def unarchive_root_feature_schema_node( + self, ontology_id: str, root_feature_schema_id: str) -> bool: """ Returns true if the root feature schema node was successfully unarchived, false otherwise Args: From 63703a71f035e0f9ef987a1e67bf267accc14743 Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Mon, 27 Feb 2023 13:15:13 -0700 Subject: [PATCH 03/23] Updated property name to match value sent back from the api --- labelbox/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/labelbox/client.py b/labelbox/client.py index 3be68990b..0dcc77ad3 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -1412,7 +1412,7 @@ def unarchive_root_feature_schema_node( headers=self.rest_endpoint_headers, ) if response.status_code == 200: - return response.json()['didUnarchive'] + return response.json()['unarchived'] else: raise labelbox.exceptions.LabelboxError( "Failed unarchive root feature schema node: ", response.text) From a761ab1fbc35a8e595a31d2fbe97520abd9ea2a5 Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Wed, 1 Mar 2023 08:37:35 -0700 Subject: [PATCH 04/23] Fix rest entpoint url --- labelbox/client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/labelbox/client.py b/labelbox/client.py index ced587227..855c9465f 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -1406,7 +1406,7 @@ def unarchive_root_feature_schema_node( Returns: bool """ - ontology_endpoint = self.rest_endpoint + "/ontologies/" + ontology_id + '/root-feature-schemas/' + root_feature_schema_id + '/unarchive' + ontology_endpoint = self.rest_endpoint + "/ontologies/" + ontology_id + '/feature-schemas/' + root_feature_schema_id + '/unarchive' response = requests.patch( ontology_endpoint, headers=self.rest_endpoint_headers, @@ -1416,7 +1416,7 @@ def unarchive_root_feature_schema_node( else: raise labelbox.exceptions.LabelboxError( "Failed unarchive root feature schema node: ", response.text) - + def get_model_slice(self, slice_id) -> ModelSlice: """ Fetches a Model Slice by ID. From f03fe0476ec9aec9e1d7eabd708c5fc95f501151 Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Wed, 1 Mar 2023 08:45:45 -0700 Subject: [PATCH 05/23] updated function name --- labelbox/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/labelbox/client.py b/labelbox/client.py index 855c9465f..1bafc9a4e 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -1396,7 +1396,7 @@ def get_catalog_slice(self, slice_id) -> CatalogSlice: res = self.execute(query_str, {'id': slice_id}) return Entity.CatalogSlice(self, res['getSavedQuery']) - def unarchive_root_feature_schema_node( + def unarchive_feature_schema_node( self, ontology_id: str, root_feature_schema_id: str) -> bool: """ Returns true if the root feature schema node was successfully unarchived, false otherwise From 285962c37fefd26b644df85291bc009491c79a24 Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Wed, 1 Mar 2023 08:53:22 -0700 Subject: [PATCH 06/23] Ran yapf formatter --- labelbox/client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/labelbox/client.py b/labelbox/client.py index 1bafc9a4e..750fd6b57 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -1396,8 +1396,8 @@ def get_catalog_slice(self, slice_id) -> CatalogSlice: res = self.execute(query_str, {'id': slice_id}) return Entity.CatalogSlice(self, res['getSavedQuery']) - def unarchive_feature_schema_node( - self, ontology_id: str, root_feature_schema_id: str) -> bool: + def unarchive_feature_schema_node(self, ontology_id: str, + root_feature_schema_id: str) -> bool: """ Returns true if the root feature schema node was successfully unarchived, false otherwise Args: From d5bfb3ab43cb678f4ef4f677955480af7bc5fefd Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Wed, 1 Mar 2023 11:31:49 -0700 Subject: [PATCH 07/23] Ran linter --- labelbox/client.py | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/labelbox/client.py b/labelbox/client.py index 750fd6b57..aff938ca4 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -156,8 +156,7 @@ def convert_value(value): if query is not None: if params is not None: params = { - key: convert_value(value) - for key, value in params.items() + key: convert_value(value) for key, value in params.items() } data = json.dumps({ 'query': query, @@ -358,18 +357,18 @@ def upload_data(self, request_data = { "operations": - json.dumps({ - "variables": { - "file": None, - "contentLength": len(content), - "sign": sign - }, - "query": - """mutation UploadFile($file: Upload!, $contentLength: Int!, + json.dumps({ + "variables": { + "file": None, + "contentLength": len(content), + "sign": sign + }, + "query": + """mutation UploadFile($file: Upload!, $contentLength: Int!, $sign: Boolean) { uploadFile(file: $file, contentLength: $contentLength, sign: $sign) {url filename} } """, - }), + }), "map": (None, json.dumps({"1": ["variables.file"]})), } response = requests.post( @@ -378,7 +377,7 @@ def upload_data(self, data=request_data, files={ "1": (filename, content, content_type) if - (filename and content_type) else content + (filename and content_type) else content }) if response.status_code == 502: @@ -666,8 +665,7 @@ def create_project(self, **kwargs) -> Project: elif queue_mode == QueueMode.Dataset: logger.warning( "QueueMode.Dataset will eventually be deprecated, and is no longer " - "recommended for new projects. Prefer QueueMode.Batch instead." - ) + "recommended for new projects. Prefer QueueMode.Batch instead.") return self._create(Entity.Project, { **kwargs, @@ -779,7 +777,7 @@ def get_data_row_ids_for_external_ids( for row in self.execute( query_str, {'externalId_in': external_ids[i:i + max_ids_per_request] - })['externalIdsToDataRowIds']: + })['externalIdsToDataRowIds']: result[row['externalId']].append(row['dataRowId']) return result @@ -1071,10 +1069,9 @@ def _format_failed_rows(rows: Dict[str, str], } """ params = { - 'globalKeyDataRowLinks': - [{utils.camel_case(key): value - for key, value in input.items()} - for input in global_key_to_data_row_inputs] + 'globalKeyDataRowLinks': [{ + utils.camel_case(key): value for key, value in input.items() + } for input in global_key_to_data_row_inputs] } assign_global_keys_to_data_rows_job = self.execute(query_str, params) @@ -1103,8 +1100,8 @@ def _format_failed_rows(rows: Dict[str, str], """ result_params = { "jobId": - assign_global_keys_to_data_rows_job["assignGlobalKeysToDataRows"] - ["jobId"] + assign_global_keys_to_data_rows_job["assignGlobalKeysToDataRows" + ]["jobId"] } # Poll job status until finished, then retrieve results @@ -1220,7 +1217,7 @@ def _format_failed_rows(rows: List[str], """ result_params = { "jobId": - data_rows_for_global_keys_job["dataRowsForGlobalKeys"]["jobId"] + data_rows_for_global_keys_job["dataRowsForGlobalKeys"]["jobId"] } # Poll job status until finished, then retrieve results @@ -1342,8 +1339,7 @@ def _format_failed_rows(rows: List[str], errors.extend( _format_failed_rows( data['notFoundGlobalKeys'], - "Failed to find data row matching provided global key") - ) + "Failed to find data row matching provided global key")) errors.extend( _format_failed_rows( data['accessDeniedGlobalKeys'], From 179ec6163505d7cf627201663facbe8dd981b2a0 Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Thu, 2 Mar 2023 11:14:40 -0700 Subject: [PATCH 08/23] Cleanup --- labelbox/client.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/labelbox/client.py b/labelbox/client.py index 94b67dbbb..c4335df8b 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -98,12 +98,6 @@ def __init__(self, 'X-User-Agent': f'python-sdk {SDK_VERSION}' } self._data_row_metadata_ontology = None - self.rest_endpoint = rest_endpoint - self.rest_endpoint_headers = { - "authorization": "Bearer %s" % self.api_key, - 'X-User-Agent': 'python-sdk 0.0.0', - 'Content-Type': 'application/json', - } @retry.Retry(predicate=retry.if_exception_type( labelbox.exceptions.InternalServerError, @@ -1593,7 +1587,7 @@ def unarchive_feature_schema_node(self, ontology_id: str, ontology_endpoint = self.rest_endpoint + "/ontologies/" + ontology_id + '/feature-schemas/' + root_feature_schema_id + '/unarchive' response = requests.patch( ontology_endpoint, - headers=self.rest_endpoint_headers, + headers=self.headers, ) if response.status_code == 200: return response.json()['unarchived'] From 3f98a70ed7bb65f28b22272ef9b55fd7d0281ba5 Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Thu, 2 Mar 2023 14:09:18 -0700 Subject: [PATCH 09/23] url encoding rest params --- labelbox/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/labelbox/client.py b/labelbox/client.py index c4335df8b..b033ef30a 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -1584,7 +1584,7 @@ def unarchive_feature_schema_node(self, ontology_id: str, Returns: bool """ - ontology_endpoint = self.rest_endpoint + "/ontologies/" + ontology_id + '/feature-schemas/' + root_feature_schema_id + '/unarchive' + ontology_endpoint = self.rest_endpoint + "/ontologies/" + urllib.parse.quote(ontology_id) + '/feature-schemas/' + urllib.parse.quote(root_feature_schema_id) + '/unarchive' response = requests.patch( ontology_endpoint, headers=self.headers, From 734dd3bb0a3b4ff0f15b3c04b7d14454c5eb71ca Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Thu, 2 Mar 2023 14:10:52 -0700 Subject: [PATCH 10/23] pr suggestions --- labelbox/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/labelbox/client.py b/labelbox/client.py index b033ef30a..ac135ee3b 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -1589,7 +1589,7 @@ def unarchive_feature_schema_node(self, ontology_id: str, ontology_endpoint, headers=self.headers, ) - if response.status_code == 200: + if response.status_code == requests.codes.ok: return response.json()['unarchived'] else: raise labelbox.exceptions.LabelboxError( From 69d98256a770d72d4f2d01aef7c0d2da46c42d28 Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Thu, 2 Mar 2023 14:11:39 -0700 Subject: [PATCH 11/23] updated error message --- labelbox/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/labelbox/client.py b/labelbox/client.py index ac135ee3b..6cce605ba 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -1593,7 +1593,7 @@ def unarchive_feature_schema_node(self, ontology_id: str, return response.json()['unarchived'] else: raise labelbox.exceptions.LabelboxError( - "Failed unarchive root feature schema node: ", response.text) + "Failed unarchive root feature schema nodee, message: ", response.text) def get_model_slice(self, slice_id) -> ModelSlice: """ From 4764f3e85dc2ce7fcff2f038389fd8790c392af2 Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Thu, 2 Mar 2023 14:12:29 -0700 Subject: [PATCH 12/23] updated error message --- labelbox/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/labelbox/client.py b/labelbox/client.py index 6cce605ba..97a275608 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -1593,7 +1593,7 @@ def unarchive_feature_schema_node(self, ontology_id: str, return response.json()['unarchived'] else: raise labelbox.exceptions.LabelboxError( - "Failed unarchive root feature schema nodee, message: ", response.text) + "Failed unarchive root feature schema node, message: ", response.text) def get_model_slice(self, slice_id) -> ModelSlice: """ From b61eb563ea7d8a81c1f2692a4fc47a0d3313615f Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Thu, 2 Mar 2023 14:30:19 -0700 Subject: [PATCH 13/23] Ran yapf formatter --- labelbox/client.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/labelbox/client.py b/labelbox/client.py index 97a275608..a3c642a06 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -1584,7 +1584,9 @@ def unarchive_feature_schema_node(self, ontology_id: str, Returns: bool """ - ontology_endpoint = self.rest_endpoint + "/ontologies/" + urllib.parse.quote(ontology_id) + '/feature-schemas/' + urllib.parse.quote(root_feature_schema_id) + '/unarchive' + ontology_endpoint = self.rest_endpoint + "/ontologies/" + urllib.parse.quote( + ontology_id) + '/feature-schemas/' + urllib.parse.quote( + root_feature_schema_id) + '/unarchive' response = requests.patch( ontology_endpoint, headers=self.headers, @@ -1593,7 +1595,8 @@ def unarchive_feature_schema_node(self, ontology_id: str, return response.json()['unarchived'] else: raise labelbox.exceptions.LabelboxError( - "Failed unarchive root feature schema node, message: ", response.text) + "Failed unarchive root feature schema node, message: ", + response.text) def get_model_slice(self, slice_id) -> ModelSlice: """ From 85e77f6ca6072d90e71ea6cab45aa998cbb6775f Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Fri, 3 Mar 2023 12:54:27 -0700 Subject: [PATCH 14/23] Added extra docs --- labelbox/client.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/labelbox/client.py b/labelbox/client.py index a3c642a06..656127c82 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -1577,7 +1577,8 @@ def get_catalog_slice(self, slice_id) -> CatalogSlice: def unarchive_feature_schema_node(self, ontology_id: str, root_feature_schema_id: str) -> bool: """ - Returns true if the root feature schema node was successfully unarchived, false otherwise + Returns true if the root feature schema node was successfully unarchived, false otherwise. + Only root level feature schema nodes can be unarchived. Args: root_feature_schema_id (str): The ID of the root level feature schema ontology_id (str): The ID of the ontology From 43b600993bc65c36662f91f230cb87e2ecf89930 Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Wed, 8 Mar 2023 12:50:55 -0700 Subject: [PATCH 15/23] Added integration test --- tests/integration/test_ontology.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/integration/test_ontology.py b/tests/integration/test_ontology.py index 5fa004ebb..632cd0310 100644 --- a/tests/integration/test_ontology.py +++ b/tests/integration/test_ontology.py @@ -5,6 +5,10 @@ import json import time +def test_unarchive_feature_schema_node(client, ontology): + feature_schema_to_unarchive = ontology.normalized['tools'][0] + result = client.unarchive_feature_schema_node(ontology.uid, feature_schema_to_unarchive['featureSchemaId']) + assert result == True def test_delete_tool_feature_from_ontology(client, ontology): feature_schema_to_delete = ontology.normalized['tools'][0] From bbc9e4f9ebf2f30ef87c98db5d5e154dfd7f7112 Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Wed, 8 Mar 2023 12:59:29 -0700 Subject: [PATCH 16/23] Ran yapf formatter --- tests/integration/test_ontology.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/integration/test_ontology.py b/tests/integration/test_ontology.py index 632cd0310..3bc4d2139 100644 --- a/tests/integration/test_ontology.py +++ b/tests/integration/test_ontology.py @@ -5,11 +5,14 @@ import json import time + def test_unarchive_feature_schema_node(client, ontology): feature_schema_to_unarchive = ontology.normalized['tools'][0] - result = client.unarchive_feature_schema_node(ontology.uid, feature_schema_to_unarchive['featureSchemaId']) + result = client.unarchive_feature_schema_node( + ontology.uid, feature_schema_to_unarchive['featureSchemaId']) assert result == True + def test_delete_tool_feature_from_ontology(client, ontology): feature_schema_to_delete = ontology.normalized['tools'][0] assert len(ontology.normalized['tools']) == 2 From 35480455f650bc831196df04a8f3be040c8ff665 Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Wed, 8 Mar 2023 14:44:54 -0700 Subject: [PATCH 17/23] Added unhappy path integration tests --- tests/integration/test_ontology.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/integration/test_ontology.py b/tests/integration/test_ontology.py index 3bc4d2139..e981fb109 100644 --- a/tests/integration/test_ontology.py +++ b/tests/integration/test_ontology.py @@ -13,6 +13,26 @@ def test_unarchive_feature_schema_node(client, ontology): assert result == True +def test_unarchive_feature_schema_node_for_non_existing_feature_schema( + client, ontology): + with pytest.raises( + Exception, + match= + "Failed to find feature schema node by id: invalid-feature-schema-id" + ): + client.unarchive_feature_schema_node(ontology.uid, + 'invalid-feature-schema-id') + + +def test_unarchive_feature_schema_node_for_non_existing_ontology( + client, ontology): + feature_schema_to_unarchive = ontology.normalized['tools'][0] + with pytest.raises(Exception, + match="Failed to find ontology by id: invalid-ontology"): + client.unarchive_feature_schema_node( + 'invalid-ontology', feature_schema_to_unarchive['featureSchemaId']) + + def test_delete_tool_feature_from_ontology(client, ontology): feature_schema_to_delete = ontology.normalized['tools'][0] assert len(ontology.normalized['tools']) == 2 From 2c45ec7cf3362b941a2630c6ef6c1ffde7b2fc00 Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Thu, 9 Mar 2023 09:35:30 -0700 Subject: [PATCH 18/23] Now raising an exception if the feature schema is not successfully archived --- labelbox/client.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/labelbox/client.py b/labelbox/client.py index e74d3ae73..22f4799cb 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -1581,7 +1581,7 @@ def get_catalog_slice(self, slice_id) -> CatalogSlice: def unarchive_feature_schema_node(self, ontology_id: str, root_feature_schema_id: str) -> bool: """ - Returns true if the root feature schema node was successfully unarchived, false otherwise. + Returns true if the root feature schema node was successfully unarchived. Only root level feature schema nodes can be unarchived. Args: root_feature_schema_id (str): The ID of the root level feature schema @@ -1597,10 +1597,14 @@ def unarchive_feature_schema_node(self, ontology_id: str, headers=self.headers, ) if response.status_code == requests.codes.ok: - return response.json()['unarchived'] + unarchived = bool(response.json()['unarchived']) + if (unarchived == False): + raise labelbox.exceptions.LabelboxError( + "Failed unarchive the feature schema.", response.text) + return unarchived else: raise labelbox.exceptions.LabelboxError( - "Failed unarchive root feature schema node, message: ", + "Failed unarchive the feature schema node, message: ", response.text) def get_model_slice(self, slice_id) -> ModelSlice: From b34b2d95103d91c64ee9fbb55894353c16b3076e Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Thu, 9 Mar 2023 09:36:32 -0700 Subject: [PATCH 19/23] cleanup --- labelbox/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/labelbox/client.py b/labelbox/client.py index 22f4799cb..44ab92ed7 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -1600,7 +1600,7 @@ def unarchive_feature_schema_node(self, ontology_id: str, unarchived = bool(response.json()['unarchived']) if (unarchived == False): raise labelbox.exceptions.LabelboxError( - "Failed unarchive the feature schema.", response.text) + "Failed unarchive the feature schema.") return unarchived else: raise labelbox.exceptions.LabelboxError( From a4640bf522fca1464fd2e8b1c0af50e971204788 Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Fri, 10 Mar 2023 10:05:32 -0700 Subject: [PATCH 20/23] moved client method to the bottom of the file to avoid conflicts --- labelbox/client.py | 58 +++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/labelbox/client.py b/labelbox/client.py index 44ab92ed7..20583304e 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -1578,35 +1578,6 @@ def get_catalog_slice(self, slice_id) -> CatalogSlice: res = self.execute(query_str, {'id': slice_id}) return Entity.CatalogSlice(self, res['getSavedQuery']) - def unarchive_feature_schema_node(self, ontology_id: str, - root_feature_schema_id: str) -> bool: - """ - Returns true if the root feature schema node was successfully unarchived. - Only root level feature schema nodes can be unarchived. - Args: - root_feature_schema_id (str): The ID of the root level feature schema - ontology_id (str): The ID of the ontology - Returns: - bool - """ - ontology_endpoint = self.rest_endpoint + "/ontologies/" + urllib.parse.quote( - ontology_id) + '/feature-schemas/' + urllib.parse.quote( - root_feature_schema_id) + '/unarchive' - response = requests.patch( - ontology_endpoint, - headers=self.headers, - ) - if response.status_code == requests.codes.ok: - unarchived = bool(response.json()['unarchived']) - if (unarchived == False): - raise labelbox.exceptions.LabelboxError( - "Failed unarchive the feature schema.") - return unarchived - else: - raise labelbox.exceptions.LabelboxError( - "Failed unarchive the feature schema node, message: ", - response.text) - def get_model_slice(self, slice_id) -> ModelSlice: """ Fetches a Model Slice by ID. @@ -1675,3 +1646,32 @@ def delete_feature_schema_from_ontology( raise labelbox.exceptions.LabelboxError( "Failed to remove feature schema from ontology, message: " + str(response.json()['message'])) + + def unarchive_feature_schema_node(self, ontology_id: str, + root_feature_schema_id: str) -> bool: + """ + Returns true if the root feature schema node was successfully unarchived. + Only root level feature schema nodes can be unarchived. + Args: + root_feature_schema_id (str): The ID of the root level feature schema + ontology_id (str): The ID of the ontology + Returns: + bool + """ + ontology_endpoint = self.rest_endpoint + "/ontologies/" + urllib.parse.quote( + ontology_id) + '/feature-schemas/' + urllib.parse.quote( + root_feature_schema_id) + '/unarchive' + response = requests.patch( + ontology_endpoint, + headers=self.headers, + ) + if response.status_code == requests.codes.ok: + unarchived = bool(response.json()['unarchived']) + if (unarchived == False): + raise labelbox.exceptions.LabelboxError( + "Failed unarchive the feature schema.") + return unarchived + else: + raise labelbox.exceptions.LabelboxError( + "Failed unarchive the feature schema node, message: ", + response.text) From 954cb910eb2a15e3c56662bb7d75f96e98bba2b9 Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Fri, 10 Mar 2023 10:08:31 -0700 Subject: [PATCH 21/23] Moved tests to the bottom of the file to avoid conflicts --- tests/integration/test_ontology.py | 53 +++++++++++++++--------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/tests/integration/test_ontology.py b/tests/integration/test_ontology.py index e981fb109..52450089f 100644 --- a/tests/integration/test_ontology.py +++ b/tests/integration/test_ontology.py @@ -6,33 +6,6 @@ import time -def test_unarchive_feature_schema_node(client, ontology): - feature_schema_to_unarchive = ontology.normalized['tools'][0] - result = client.unarchive_feature_schema_node( - ontology.uid, feature_schema_to_unarchive['featureSchemaId']) - assert result == True - - -def test_unarchive_feature_schema_node_for_non_existing_feature_schema( - client, ontology): - with pytest.raises( - Exception, - match= - "Failed to find feature schema node by id: invalid-feature-schema-id" - ): - client.unarchive_feature_schema_node(ontology.uid, - 'invalid-feature-schema-id') - - -def test_unarchive_feature_schema_node_for_non_existing_ontology( - client, ontology): - feature_schema_to_unarchive = ontology.normalized['tools'][0] - with pytest.raises(Exception, - match="Failed to find ontology by id: invalid-ontology"): - client.unarchive_feature_schema_node( - 'invalid-ontology', feature_schema_to_unarchive['featureSchemaId']) - - def test_delete_tool_feature_from_ontology(client, ontology): feature_schema_to_delete = ontology.normalized['tools'][0] assert len(ontology.normalized['tools']) == 2 @@ -236,3 +209,29 @@ def test_ontology_create_read(client, rand_gen): assert _get_attr_stringify_json(created_ontology, attr) == _get_attr_stringify_json( queried_ontology, attr) + +def test_unarchive_feature_schema_node(client, ontology): + feature_schema_to_unarchive = ontology.normalized['tools'][0] + result = client.unarchive_feature_schema_node( + ontology.uid, feature_schema_to_unarchive['featureSchemaId']) + assert result == True + + +def test_unarchive_feature_schema_node_for_non_existing_feature_schema( + client, ontology): + with pytest.raises( + Exception, + match= + "Failed to find feature schema node by id: invalid-feature-schema-id" + ): + client.unarchive_feature_schema_node(ontology.uid, + 'invalid-feature-schema-id') + + +def test_unarchive_feature_schema_node_for_non_existing_ontology( + client, ontology): + feature_schema_to_unarchive = ontology.normalized['tools'][0] + with pytest.raises(Exception, + match="Failed to find ontology by id: invalid-ontology"): + client.unarchive_feature_schema_node( + 'invalid-ontology', feature_schema_to_unarchive['featureSchemaId']) \ No newline at end of file From 65b814bf8d3e78793c4d83a26ea2c4cb3248fe39 Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Fri, 10 Mar 2023 10:14:49 -0700 Subject: [PATCH 22/23] Now returning None from the client method --- labelbox/client.py | 14 ++++++-------- tests/integration/test_ontology.py | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/labelbox/client.py b/labelbox/client.py index ae222893c..48ec6a9fc 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -1687,15 +1687,15 @@ def delete_feature_schema_from_ontology( str(response.json()['message'])) def unarchive_feature_schema_node(self, ontology_id: str, - root_feature_schema_id: str) -> bool: + root_feature_schema_id: str) -> None: """ - Returns true if the root feature schema node was successfully unarchived. + Unarchives a feature schema node in an ontology. Only root level feature schema nodes can be unarchived. Args: - root_feature_schema_id (str): The ID of the root level feature schema ontology_id (str): The ID of the ontology + root_feature_schema_id (str): The ID of the root level feature schema Returns: - bool + None """ ontology_endpoint = self.rest_endpoint + "/ontologies/" + urllib.parse.quote( ontology_id) + '/feature-schemas/' + urllib.parse.quote( @@ -1705,11 +1705,9 @@ def unarchive_feature_schema_node(self, ontology_id: str, headers=self.headers, ) if response.status_code == requests.codes.ok: - unarchived = bool(response.json()['unarchived']) - if (unarchived == False): + if not bool(response.json()['unarchived']): raise labelbox.exceptions.LabelboxError( - "Failed unarchive the feature schema.") - return unarchived + "Failed unarchive the feature schema.") else: raise labelbox.exceptions.LabelboxError( "Failed unarchive the feature schema node, message: ", diff --git a/tests/integration/test_ontology.py b/tests/integration/test_ontology.py index dd1cbe31d..ed9e796c3 100644 --- a/tests/integration/test_ontology.py +++ b/tests/integration/test_ontology.py @@ -251,7 +251,7 @@ def test_unarchive_feature_schema_node(client, ontology): feature_schema_to_unarchive = ontology.normalized['tools'][0] result = client.unarchive_feature_schema_node( ontology.uid, feature_schema_to_unarchive['featureSchemaId']) - assert result == True + assert result == None def test_unarchive_feature_schema_node_for_non_existing_feature_schema( From 5f8924523ae8c32c44cbb9db7d2878ced9d5af31 Mon Sep 17 00:00:00 2001 From: Tim Kerr Date: Fri, 10 Mar 2023 10:15:22 -0700 Subject: [PATCH 23/23] Ran the formatter --- labelbox/client.py | 4 ++-- tests/integration/test_ontology.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/labelbox/client.py b/labelbox/client.py index 48ec6a9fc..c7a1eb3c7 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -1685,7 +1685,7 @@ def delete_feature_schema_from_ontology( raise labelbox.exceptions.LabelboxError( "Failed to remove feature schema from ontology, message: " + str(response.json()['message'])) - + def unarchive_feature_schema_node(self, ontology_id: str, root_feature_schema_id: str) -> None: """ @@ -1707,7 +1707,7 @@ def unarchive_feature_schema_node(self, ontology_id: str, if response.status_code == requests.codes.ok: if not bool(response.json()['unarchived']): raise labelbox.exceptions.LabelboxError( - "Failed unarchive the feature schema.") + "Failed unarchive the feature schema.") else: raise labelbox.exceptions.LabelboxError( "Failed unarchive the feature schema node, message: ", diff --git a/tests/integration/test_ontology.py b/tests/integration/test_ontology.py index ed9e796c3..e95e9eff7 100644 --- a/tests/integration/test_ontology.py +++ b/tests/integration/test_ontology.py @@ -247,6 +247,7 @@ def test_ontology_create_read(client, rand_gen): attr) == _get_attr_stringify_json( queried_ontology, attr) + def test_unarchive_feature_schema_node(client, ontology): feature_schema_to_unarchive = ontology.normalized['tools'][0] result = client.unarchive_feature_schema_node( @@ -271,4 +272,4 @@ def test_unarchive_feature_schema_node_for_non_existing_ontology( with pytest.raises(Exception, match="Failed to find ontology by id: invalid-ontology"): client.unarchive_feature_schema_node( - 'invalid-ontology', feature_schema_to_unarchive['featureSchemaId']) \ No newline at end of file + 'invalid-ontology', feature_schema_to_unarchive['featureSchemaId'])