octostar-python-client 0.1.759__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- octostar/__init__.py +9 -0
- octostar/api/__init__.py +1 -0
- octostar/api/apps/__init__.py +0 -0
- octostar/api/apps/deploy_app.py +210 -0
- octostar/api/apps/execute_app_job.py +188 -0
- octostar/api/apps/get_app_logs.py +210 -0
- octostar/api/apps/get_apps_url.py +188 -0
- octostar/api/apps/get_job_logs.py +210 -0
- octostar/api/apps/get_job_progress.py +162 -0
- octostar/api/apps/kill_job.py +160 -0
- octostar/api/apps/list_app_jobs.py +276 -0
- octostar/api/apps/list_apps.py +251 -0
- octostar/api/apps/set_job_progress.py +216 -0
- octostar/api/apps/undeploy_app.py +160 -0
- octostar/api/metadata/__init__.py +0 -0
- octostar/api/metadata/get_version.py +232 -0
- octostar/api/metadata/get_whoami.py +232 -0
- octostar/api/notifications/__init__.py +0 -0
- octostar/api/notifications/delete_stream.py +222 -0
- octostar/api/notifications/get_subscriptions.py +240 -0
- octostar/api/notifications/publish_notification.py +275 -0
- octostar/api/notifications/pull_events_from_stream.py +282 -0
- octostar/api/notifications/push_event_to_stream.py +265 -0
- octostar/api/notifications/toast.py +264 -0
- octostar/api/ontology/__init__.py +0 -0
- octostar/api/ontology/fetch_ontology_data.py +275 -0
- octostar/api/ontology/get_ontologies.py +237 -0
- octostar/api/ontology/multi_query.py +297 -0
- octostar/api/ontology/query.py +276 -0
- octostar/api/pipeline/__init__.py +1 -0
- octostar/api/pipeline/get_processing_status.py +185 -0
- octostar/api/pipeline/update_processing_status.py +164 -0
- octostar/api/search/__init__.py +0 -0
- octostar/api/search/get_annotations.py +153 -0
- octostar/api/workspace_data/__init__.py +0 -0
- octostar/api/workspace_data/delete_blob.py +212 -0
- octostar/api/workspace_data/delete_entities.py +326 -0
- octostar/api/workspace_data/download_blob.py +235 -0
- octostar/api/workspace_data/get_attachment.py +336 -0
- octostar/api/workspace_data/get_files_tree.py +397 -0
- octostar/api/workspace_data/upload_blob.py +235 -0
- octostar/api/workspace_data/upsert_entities.py +284 -0
- octostar/api/workspace_permissions/__init__.py +0 -0
- octostar/api/workspace_permissions/get_permissions.py +325 -0
- octostar/api/workspace_tags/__init__.py +0 -0
- octostar/api/workspace_tags/delete_tag_from_entities.py +141 -0
- octostar/api/workspace_tags/tag_entities.py +180 -0
- octostar/client.py +492 -0
- octostar/errors.py +50 -0
- octostar/models/__init__.py +249 -0
- octostar/models/acknowledgement.py +74 -0
- octostar/models/acknowledgement_with_data.py +82 -0
- octostar/models/app_status.py +239 -0
- octostar/models/app_status_annotations.py +66 -0
- octostar/models/app_status_labels.py +69 -0
- octostar/models/app_with_url.py +82 -0
- octostar/models/child_processing_status.py +118 -0
- octostar/models/delete_entities_response_401.py +74 -0
- octostar/models/delete_entities_response_409.py +82 -0
- octostar/models/delete_entities_response_500.py +82 -0
- octostar/models/delete_stream_response_401.py +74 -0
- octostar/models/delete_tag_from_entities_response_401.py +74 -0
- octostar/models/deploy_app_json_body.py +90 -0
- octostar/models/deploy_app_json_body_secrets.py +65 -0
- octostar/models/deploy_app_response_200.py +98 -0
- octostar/models/deploy_app_response_200_data.py +60 -0
- octostar/models/deploy_app_response_400.py +82 -0
- octostar/models/deploy_app_response_403.py +82 -0
- octostar/models/deploy_app_response_404.py +82 -0
- octostar/models/deploy_app_response_409.py +82 -0
- octostar/models/deploy_app_response_500.py +82 -0
- octostar/models/entity.py +80 -0
- octostar/models/entity_response.py +99 -0
- octostar/models/entity_response_s3_urls.py +93 -0
- octostar/models/entity_response_s3_urls_additional_property.py +105 -0
- octostar/models/entity_response_s3_urls_additional_property_fields.py +114 -0
- octostar/models/execute_app_job_json_body.py +151 -0
- octostar/models/execute_app_job_json_body_annotation.py +65 -0
- octostar/models/execute_app_job_response_401.py +74 -0
- octostar/models/fetch_ontology_data_response_200.py +60 -0
- octostar/models/fetch_ontology_data_response_401.py +74 -0
- octostar/models/fetch_ontology_data_response_500.py +82 -0
- octostar/models/get_app_logs_response_401.py +74 -0
- octostar/models/get_app_logs_response_404.py +74 -0
- octostar/models/get_app_logs_response_500.py +82 -0
- octostar/models/get_apps_url_json_body.py +76 -0
- octostar/models/get_apps_url_response_401.py +74 -0
- octostar/models/get_apps_url_response_500.py +82 -0
- octostar/models/get_attachment_response_200.py +74 -0
- octostar/models/get_attachment_response_401.py +74 -0
- octostar/models/get_files_tree_response_200.py +106 -0
- octostar/models/get_files_tree_response_200_status.py +8 -0
- octostar/models/get_files_tree_response_400.py +111 -0
- octostar/models/get_files_tree_response_400_data.py +60 -0
- octostar/models/get_files_tree_response_400_status.py +8 -0
- octostar/models/get_files_tree_response_401.py +74 -0
- octostar/models/get_files_tree_response_500.py +111 -0
- octostar/models/get_files_tree_response_500_data.py +60 -0
- octostar/models/get_files_tree_response_500_status.py +8 -0
- octostar/models/get_job_logs_response_401.py +74 -0
- octostar/models/get_job_logs_response_404.py +74 -0
- octostar/models/get_job_logs_response_500.py +82 -0
- octostar/models/get_job_progress_response_401.py +74 -0
- octostar/models/get_object_response_401.py +74 -0
- octostar/models/get_ontologies_response_401.py +74 -0
- octostar/models/get_ontologies_response_500.py +81 -0
- octostar/models/get_permissions_response_200.py +98 -0
- octostar/models/get_permissions_response_400.py +82 -0
- octostar/models/get_permissions_response_401.py +74 -0
- octostar/models/get_permissions_response_500.py +82 -0
- octostar/models/get_processing_status_response_200.py +104 -0
- octostar/models/get_processing_status_response_200_data.py +87 -0
- octostar/models/get_processing_status_response_400.py +82 -0
- octostar/models/get_processing_status_response_500.py +82 -0
- octostar/models/get_subscriptions_response_200_item.py +74 -0
- octostar/models/get_version_response_200.py +74 -0
- octostar/models/get_version_response_404.py +74 -0
- octostar/models/get_whoami_response_200.py +129 -0
- octostar/models/get_whoami_response_401.py +74 -0
- octostar/models/insert_entity.py +114 -0
- octostar/models/insert_entity_base.py +266 -0
- octostar/models/insert_entity_relationships_item.py +107 -0
- octostar/models/insert_entity_request.py +94 -0
- octostar/models/internal_server_error.py +82 -0
- octostar/models/job_execution_result.py +146 -0
- octostar/models/job_status.py +196 -0
- octostar/models/job_status_labels.py +60 -0
- octostar/models/job_with_url.py +82 -0
- octostar/models/kill_job_response_401.py +74 -0
- octostar/models/list_app_jobs_response_401.py +74 -0
- octostar/models/list_app_jobs_response_500.py +82 -0
- octostar/models/list_apps_response_401.py +74 -0
- octostar/models/list_apps_response_500.py +82 -0
- octostar/models/multi_query_json_body.py +100 -0
- octostar/models/multi_query_json_body_queries_item.py +80 -0
- octostar/models/multi_query_response_400.py +82 -0
- octostar/models/multi_query_response_401.py +74 -0
- octostar/models/not_found_error.py +74 -0
- octostar/models/octostar_event.py +96 -0
- octostar/models/octostar_event_octostar_payload.py +100 -0
- octostar/models/octostar_event_octostar_payload_level.py +11 -0
- octostar/models/os_notification.py +122 -0
- octostar/models/processing_status.py +262 -0
- octostar/models/processing_status_code.py +14 -0
- octostar/models/progress_request.py +73 -0
- octostar/models/publish_notification_response_401.py +74 -0
- octostar/models/pull_events_from_stream_response_401.py +74 -0
- octostar/models/push_event_to_stream_response_401.py +74 -0
- octostar/models/query_json_body.py +101 -0
- octostar/models/query_json_body_params.py +60 -0
- octostar/models/query_response_400.py +82 -0
- octostar/models/query_response_401.py +74 -0
- octostar/models/set_job_progress_response_401.py +74 -0
- octostar/models/string_to_value_label_map.py +99 -0
- octostar/models/string_to_value_label_map_data.py +89 -0
- octostar/models/string_to_value_label_map_data_additional_property.py +80 -0
- octostar/models/successful_get_tags.py +103 -0
- octostar/models/successful_insertion.py +98 -0
- octostar/models/tag_entities_response_401.py +74 -0
- octostar/models/toast_level.py +11 -0
- octostar/models/toast_response_401.py +74 -0
- octostar/models/undeploy_app_response_401.py +74 -0
- octostar/models/update_processing_status_response_200.py +82 -0
- octostar/models/update_processing_status_response_400.py +82 -0
- octostar/models/update_processing_status_response_500.py +82 -0
- octostar/models/upsert_entities_response_401.py +74 -0
- octostar/models/upsert_entity.py +114 -0
- octostar/models/upsert_entity_base.py +266 -0
- octostar/models/upsert_entity_relationships_item.py +107 -0
- octostar/py.typed +1 -0
- octostar/types.py +54 -0
- octostar/utils/__init__.py +15 -0
- octostar/utils/chat/__init__.py +0 -0
- octostar/utils/chat/chat.py +513 -0
- octostar/utils/chat/detokenize.py +105 -0
- octostar/utils/chat/get_default_model.py +50 -0
- octostar/utils/chat/list_models.py +91 -0
- octostar/utils/chat/tokenize.py +105 -0
- octostar/utils/commons.py +226 -0
- octostar/utils/exceptions.py +134 -0
- octostar/utils/jobs/__init__.py +0 -0
- octostar/utils/jobs/apps/__init__.py +0 -0
- octostar/utils/jobs/apps/deploy_app.py +81 -0
- octostar/utils/jobs/apps/execute_app_job.py +114 -0
- octostar/utils/jobs/apps/get_app_logs.py +113 -0
- octostar/utils/jobs/apps/get_app_secret.py +102 -0
- octostar/utils/jobs/apps/get_apps_url.py +73 -0
- octostar/utils/jobs/apps/list_app_jobs.py +62 -0
- octostar/utils/jobs/apps/list_apps.py +126 -0
- octostar/utils/jobs/apps/undeploy_app.py +48 -0
- octostar/utils/jobs/get_job_logs.py +113 -0
- octostar/utils/jobs/get_job_progress.py +76 -0
- octostar/utils/jobs/kill_job.py +47 -0
- octostar/utils/jobs/set_job_progress.py +67 -0
- octostar/utils/meta/__init__.py +0 -0
- octostar/utils/meta/get_version.py +30 -0
- octostar/utils/meta/get_whoami.py +30 -0
- octostar/utils/notifications/__init__.py +0 -0
- octostar/utils/notifications/delete_stream.py +58 -0
- octostar/utils/notifications/get_my_subscriptions.py +49 -0
- octostar/utils/notifications/publish_notification.py +73 -0
- octostar/utils/notifications/pull_event_from_stream.py +63 -0
- octostar/utils/notifications/pull_events_from_stream.py +64 -0
- octostar/utils/notifications/push_event_to_stream.py +109 -0
- octostar/utils/notifications/push_events_to_stream.py +137 -0
- octostar/utils/notifications/toast.py +92 -0
- octostar/utils/ontology/__init__.py +10 -0
- octostar/utils/ontology/fetch_ontology_data.py +141 -0
- octostar/utils/ontology/get_ontologies.py +55 -0
- octostar/utils/ontology/multiquery_ontology.py +287 -0
- octostar/utils/ontology/query_ontology.py +186 -0
- octostar/utils/pipeline/__init__.py +1 -0
- octostar/utils/pipeline/get_processing_status.py +230 -0
- octostar/utils/pipeline/update_processing_status.py +286 -0
- octostar/utils/search/__init__.py +11 -0
- octostar/utils/search/bulk_update.py +138 -0
- octostar/utils/search/count.py +117 -0
- octostar/utils/search/get_entity_annotations.py +304 -0
- octostar/utils/search/get_index_definition.py +111 -0
- octostar/utils/search/multi_search.py +129 -0
- octostar/utils/workspace/__init__.py +0 -0
- octostar/utils/workspace/delete_entities.py +247 -0
- octostar/utils/workspace/delete_entity.py +81 -0
- octostar/utils/workspace/delete_relationship.py +78 -0
- octostar/utils/workspace/delete_relationships.py +85 -0
- octostar/utils/workspace/delete_temporary_blob.py +85 -0
- octostar/utils/workspace/extract_entities.py +140 -0
- octostar/utils/workspace/get_filepath_from_item.py +85 -0
- octostar/utils/workspace/get_filepaths_from_items.py +100 -0
- octostar/utils/workspace/get_files_tree.py +102 -0
- octostar/utils/workspace/get_item_from_filepath.py +102 -0
- octostar/utils/workspace/get_items_from_filepaths.py +108 -0
- octostar/utils/workspace/linkcharts/__init__.py +0 -0
- octostar/utils/workspace/linkcharts/create_linkchart.py +241 -0
- octostar/utils/workspace/permissions/PermissionLevel.py +8 -0
- octostar/utils/workspace/permissions/__init__.py +1 -0
- octostar/utils/workspace/permissions/get_permissions.py +81 -0
- octostar/utils/workspace/read_attachment.py +284 -0
- octostar/utils/workspace/read_file.py +113 -0
- octostar/utils/workspace/read_temporary_blob.py +428 -0
- octostar/utils/workspace/saved_searches/__init__.py +0 -0
- octostar/utils/workspace/saved_searches/create_saved_search.py +183 -0
- octostar/utils/workspace/tags/__init__.py +0 -0
- octostar/utils/workspace/tags/delete_tag_from_entities.py +96 -0
- octostar/utils/workspace/tags/tag_entities.py +175 -0
- octostar/utils/workspace/upsert_entities.py +268 -0
- octostar/utils/workspace/upsert_entity.py +110 -0
- octostar/utils/workspace/upsert_relationship.py +128 -0
- octostar/utils/workspace/upsert_relationships.py +194 -0
- octostar/utils/workspace/write_attachment.py +263 -0
- octostar/utils/workspace/write_file.py +335 -0
- octostar/utils/workspace/write_temporary_blob.py +218 -0
- octostar_python_client-0.1.759.dist-info/METADATA +159 -0
- octostar_python_client-0.1.759.dist-info/RECORD +257 -0
- octostar_python_client-0.1.759.dist-info/WHEEL +5 -0
- octostar_python_client-0.1.759.dist-info/licenses/LICENSE +21 -0
- octostar_python_client-0.1.759.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import asyncio as _asyncio
|
|
2
|
+
import logging
|
|
3
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
4
|
+
from typing import Dict, List
|
|
5
|
+
from urllib.parse import quote
|
|
6
|
+
|
|
7
|
+
import httpx
|
|
8
|
+
|
|
9
|
+
_logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
from ...api.workspace_data import delete_entities
|
|
12
|
+
from ..ontology import query_ontology
|
|
13
|
+
from ...client import Client
|
|
14
|
+
from ..exceptions import ApiConnectionError
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _files_delete_url(client: Client, os_workspace: str, os_entity_uid: str) -> str:
|
|
18
|
+
base = client.get_base_url_v1()
|
|
19
|
+
return f"{base}/api/v1/files/delete-file/{quote(os_workspace, safe='')}/{quote(os_entity_uid, safe='')}"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _query_survivors_sync(os_entity_uids: List[str], client: Client) -> Dict[str, str]:
|
|
23
|
+
"""Return {entity_uid: os_workspace} for every UID that still exists."""
|
|
24
|
+
uids_text = ", ".join(f"'{uid}'" for uid in os_entity_uids)
|
|
25
|
+
rows = (
|
|
26
|
+
query_ontology.sync(
|
|
27
|
+
f"SELECT `os_entity_uid`, `os_workspace` FROM `timbr`.`os_workspace_item` WHERE `os_entity_uid` IN ({uids_text})",
|
|
28
|
+
client=client,
|
|
29
|
+
)
|
|
30
|
+
or []
|
|
31
|
+
)
|
|
32
|
+
return {
|
|
33
|
+
row["os_entity_uid"]: row["os_workspace"]
|
|
34
|
+
for row in rows
|
|
35
|
+
if row.get("os_entity_uid") and row.get("os_workspace")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
async def _query_survivors_async(
|
|
40
|
+
os_entity_uids: List[str], client: Client
|
|
41
|
+
) -> Dict[str, str]:
|
|
42
|
+
"""Return {entity_uid: os_workspace} for every UID that still exists."""
|
|
43
|
+
uids_text = ", ".join(f"'{uid}'" for uid in os_entity_uids)
|
|
44
|
+
rows = (
|
|
45
|
+
await query_ontology.asyncio(
|
|
46
|
+
f"SELECT `os_entity_uid`, `os_workspace` FROM `timbr`.`os_workspace_item` WHERE `os_entity_uid` IN ({uids_text})",
|
|
47
|
+
client=client,
|
|
48
|
+
)
|
|
49
|
+
or []
|
|
50
|
+
)
|
|
51
|
+
return {
|
|
52
|
+
row["os_entity_uid"]: row["os_workspace"]
|
|
53
|
+
for row in rows
|
|
54
|
+
if row.get("os_entity_uid") and row.get("os_workspace")
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _files_delete_one_sync(
|
|
59
|
+
os_workspace: str, os_entity_uid: str, client: Client
|
|
60
|
+
) -> bool:
|
|
61
|
+
"""DELETE /api/v1/files/delete-file/{os_workspace}/{entity_uid}. Returns True on 204, False on 404."""
|
|
62
|
+
url = _files_delete_url(client, os_workspace, os_entity_uid)
|
|
63
|
+
with httpx.Client(verify=client.verify_ssl) as httpx_client:
|
|
64
|
+
resp = httpx_client.delete(
|
|
65
|
+
url,
|
|
66
|
+
headers=client.get_headers(),
|
|
67
|
+
timeout=client.get_timeout(),
|
|
68
|
+
follow_redirects=client.follow_redirects,
|
|
69
|
+
)
|
|
70
|
+
if resp.status_code == 204:
|
|
71
|
+
return True
|
|
72
|
+
if resp.status_code == 404:
|
|
73
|
+
return False
|
|
74
|
+
raise ApiConnectionError("delete_entities (files fallback)", resp, client)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
async def _files_delete_one_async(
|
|
78
|
+
os_workspace: str, os_entity_uid: str, client: Client
|
|
79
|
+
) -> bool:
|
|
80
|
+
"""DELETE /api/v1/files/delete-file/{os_workspace}/{entity_uid}. Returns True on 204, False on 404."""
|
|
81
|
+
url = _files_delete_url(client, os_workspace, os_entity_uid)
|
|
82
|
+
async with httpx.AsyncClient(verify=client.verify_ssl) as httpx_client:
|
|
83
|
+
resp = await httpx_client.delete(
|
|
84
|
+
url,
|
|
85
|
+
headers=client.get_headers(),
|
|
86
|
+
timeout=client.get_timeout(),
|
|
87
|
+
follow_redirects=client.follow_redirects,
|
|
88
|
+
)
|
|
89
|
+
if resp.status_code == 204:
|
|
90
|
+
return True
|
|
91
|
+
if resp.status_code == 404:
|
|
92
|
+
return False
|
|
93
|
+
raise ApiConnectionError("delete_entities (files fallback)", resp, client)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def sync(
|
|
97
|
+
os_entity_uids: List[str],
|
|
98
|
+
safe: bool = False,
|
|
99
|
+
raise_on_missing: bool = False,
|
|
100
|
+
client: Client = None,
|
|
101
|
+
):
|
|
102
|
+
"""
|
|
103
|
+
# Delete a list of local entities given their IDs
|
|
104
|
+
|
|
105
|
+
## Arguments
|
|
106
|
+
- `os_entity_uids`: The list of IDs
|
|
107
|
+
- `safe`: Whether to raise a ValueError before removal if some entities in the list do not exist
|
|
108
|
+
- `raise_on_missing`: Whether to raise a ConnectionError if some of the entities could not be deleted
|
|
109
|
+
- `client`: The Client with which to connect to Octostar. If None, the default one is used
|
|
110
|
+
|
|
111
|
+
## Returns
|
|
112
|
+
The number of successfully deleted entities
|
|
113
|
+
|
|
114
|
+
## Raises
|
|
115
|
+
- `ValueError`: If the list of IDs contain invalid entries (and safe is enabled)
|
|
116
|
+
- `ApiConnectionError`: If the request was unsuccessful on the server
|
|
117
|
+
- `ConnectionError`: If some of the entities could not be removed (and raise_on_missing is enabled)
|
|
118
|
+
"""
|
|
119
|
+
assert len(os_entity_uids) > 0
|
|
120
|
+
if safe:
|
|
121
|
+
uids_text = ", ".join(f"'{uid}'" for uid in os_entity_uids)
|
|
122
|
+
uids = query_ontology.sync(
|
|
123
|
+
f"SELECT `os_entity_uid` FROM `timbr`.`os_thing` WHERE `os_entity_uid` IN ({uids_text})",
|
|
124
|
+
client=client,
|
|
125
|
+
)
|
|
126
|
+
if len(uids or []) < len(os_entity_uids):
|
|
127
|
+
raise ValueError("Attempting to remove an entity which does not exist!")
|
|
128
|
+
|
|
129
|
+
response = delete_entities.sync_detailed(json_body=os_entity_uids, client=client)
|
|
130
|
+
if response.status_code != 200:
|
|
131
|
+
raise ApiConnectionError("delete_entities", response, client)
|
|
132
|
+
deleted = response.parsed.additional_properties.get("deleted_count", 0)
|
|
133
|
+
|
|
134
|
+
if deleted >= len(os_entity_uids):
|
|
135
|
+
return deleted
|
|
136
|
+
|
|
137
|
+
# v1/entities/delete silently ignores certain entity types. Query for any survivors and fall back to the
|
|
138
|
+
# v1/files/delete-file endpoint in parallel, which handles the remaining entity types.
|
|
139
|
+
survivors = _query_survivors_sync(os_entity_uids, client)
|
|
140
|
+
if not survivors:
|
|
141
|
+
total = deleted
|
|
142
|
+
if total < len(os_entity_uids):
|
|
143
|
+
_logger.warning("Deleted only %d/%d entities", total, len(os_entity_uids))
|
|
144
|
+
if raise_on_missing:
|
|
145
|
+
raise ConnectionError(
|
|
146
|
+
"Failed to delete some entities! (likely they did not exist prior to this call)"
|
|
147
|
+
)
|
|
148
|
+
return total
|
|
149
|
+
|
|
150
|
+
files_deleted = 0
|
|
151
|
+
max_workers = min(len(survivors), 10)
|
|
152
|
+
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
153
|
+
futures = {
|
|
154
|
+
executor.submit(_files_delete_one_sync, ws, uid, client): uid
|
|
155
|
+
for uid, ws in survivors.items()
|
|
156
|
+
}
|
|
157
|
+
for future in as_completed(futures):
|
|
158
|
+
uid = futures[future]
|
|
159
|
+
try:
|
|
160
|
+
if future.result():
|
|
161
|
+
files_deleted += 1
|
|
162
|
+
except Exception as e:
|
|
163
|
+
_logger.error("files fallback delete failed for %s: %s", uid, e)
|
|
164
|
+
|
|
165
|
+
total = deleted + files_deleted
|
|
166
|
+
if total < len(os_entity_uids):
|
|
167
|
+
_logger.warning("Deleted only %d/%d entities", total, len(os_entity_uids))
|
|
168
|
+
if raise_on_missing:
|
|
169
|
+
raise ConnectionError(
|
|
170
|
+
"Failed to delete some entities! (likely they did not exist prior to this call)"
|
|
171
|
+
)
|
|
172
|
+
return total
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
async def asyncio(
|
|
176
|
+
os_entity_uids: List[str],
|
|
177
|
+
safe: bool = False,
|
|
178
|
+
raise_on_missing: bool = False,
|
|
179
|
+
client: Client = None,
|
|
180
|
+
):
|
|
181
|
+
"""
|
|
182
|
+
# Delete asynchronously a list of local entities given their IDs
|
|
183
|
+
|
|
184
|
+
## Arguments
|
|
185
|
+
(Same as sync function)
|
|
186
|
+
|
|
187
|
+
## Returns
|
|
188
|
+
The number of successfully deleted entities
|
|
189
|
+
|
|
190
|
+
## Raises
|
|
191
|
+
- `ValueError`: If the list of IDs contain invalid entries (and safe is enabled)
|
|
192
|
+
- `ApiConnectionError`: If the request was unsuccessful on the server
|
|
193
|
+
- `ConnectionError`: If some of the entities could not be removed (and raise_on_missing is enabled)
|
|
194
|
+
"""
|
|
195
|
+
assert len(os_entity_uids) > 0
|
|
196
|
+
if safe:
|
|
197
|
+
uids_text = ", ".join(f"'{uid}'" for uid in os_entity_uids)
|
|
198
|
+
uids = await query_ontology.asyncio(
|
|
199
|
+
f"SELECT `os_entity_uid` FROM `timbr`.`os_thing` WHERE `os_entity_uid` IN ({uids_text})",
|
|
200
|
+
client=client,
|
|
201
|
+
)
|
|
202
|
+
if len(uids or []) < len(os_entity_uids):
|
|
203
|
+
raise ValueError("Attempting to remove an entity which does not exist!")
|
|
204
|
+
|
|
205
|
+
response = await delete_entities.asyncio_detailed(
|
|
206
|
+
json_body=os_entity_uids, client=client
|
|
207
|
+
)
|
|
208
|
+
if response.status_code != 200:
|
|
209
|
+
raise ApiConnectionError("delete_entities", response, client)
|
|
210
|
+
deleted = response.parsed.additional_properties.get("deleted_count", 0)
|
|
211
|
+
|
|
212
|
+
if deleted >= len(os_entity_uids):
|
|
213
|
+
return deleted
|
|
214
|
+
|
|
215
|
+
# v1/entities/delete silently ignores certain entity types. Query for any survivors and fall back to the
|
|
216
|
+
# v1/files/delete-file endpoint in parallel, which handles the remaining entity types.
|
|
217
|
+
survivors = await _query_survivors_async(os_entity_uids, client)
|
|
218
|
+
if not survivors:
|
|
219
|
+
total = deleted
|
|
220
|
+
if total < len(os_entity_uids):
|
|
221
|
+
_logger.warning("Deleted only %d/%d entities", total, len(os_entity_uids))
|
|
222
|
+
if raise_on_missing:
|
|
223
|
+
raise ConnectionError(
|
|
224
|
+
"Failed to delete some entities! (likely they did not exist prior to this call)"
|
|
225
|
+
)
|
|
226
|
+
return total
|
|
227
|
+
|
|
228
|
+
results = await _asyncio.gather(
|
|
229
|
+
*[_files_delete_one_async(ws, uid, client) for uid, ws in survivors.items()],
|
|
230
|
+
return_exceptions=True,
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
files_deleted = 0
|
|
234
|
+
for uid, result in zip(survivors.keys(), results):
|
|
235
|
+
if isinstance(result, Exception):
|
|
236
|
+
_logger.error("files fallback delete failed for %s: %s", uid, result)
|
|
237
|
+
elif result:
|
|
238
|
+
files_deleted += 1
|
|
239
|
+
|
|
240
|
+
total = deleted + files_deleted
|
|
241
|
+
if total < len(os_entity_uids):
|
|
242
|
+
_logger.warning("Deleted only %d/%d entities", total, len(os_entity_uids))
|
|
243
|
+
if raise_on_missing:
|
|
244
|
+
raise ConnectionError(
|
|
245
|
+
"Failed to delete some entities! (likely they did not exist prior to this call)"
|
|
246
|
+
)
|
|
247
|
+
return total
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
_logger = logging.getLogger(__name__)
|
|
4
|
+
|
|
5
|
+
from ..ontology import query_ontology
|
|
6
|
+
from ...client import Client
|
|
7
|
+
from . import delete_entities as _delete_entities
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def sync(
|
|
11
|
+
os_entity_uid: str,
|
|
12
|
+
safe: bool = False,
|
|
13
|
+
raise_on_missing: bool = False,
|
|
14
|
+
client: Client = None,
|
|
15
|
+
):
|
|
16
|
+
"""
|
|
17
|
+
# Delete a local entity given its ID
|
|
18
|
+
|
|
19
|
+
## Arguments
|
|
20
|
+
- `os_entity_uid`: The ID of the entity to delete
|
|
21
|
+
- `safe`: Whether to raise a ValueError before removal if the entity does not exist
|
|
22
|
+
- `raise_on_missing`: Whether to raise a ConnectionError if the entity could not be deleted
|
|
23
|
+
- `client`: The Client with which to connect to Octostar. If None, the default one is used
|
|
24
|
+
|
|
25
|
+
## Returns
|
|
26
|
+
True if the entity was successfully deleted, False if no entity was deleted
|
|
27
|
+
|
|
28
|
+
## Raises
|
|
29
|
+
- `ValueError`: If the ID is not a valid entity ID (and safe is enabled)
|
|
30
|
+
- `ApiConnectionError`: If the request was unsuccessful on the server
|
|
31
|
+
- `ConnectionError`: If the entity could not be removed (and raise_on_missing is enabled)
|
|
32
|
+
"""
|
|
33
|
+
if safe:
|
|
34
|
+
uids = query_ontology.sync(
|
|
35
|
+
f"SELECT `os_entity_uid` FROM `timbr`.`os_thing` WHERE `os_entity_uid`='{os_entity_uid}'",
|
|
36
|
+
client=client,
|
|
37
|
+
)
|
|
38
|
+
if not uids:
|
|
39
|
+
raise ValueError("Attempting to remove an entity which does not exist!")
|
|
40
|
+
|
|
41
|
+
deleted = _delete_entities.sync(
|
|
42
|
+
[os_entity_uid], raise_on_missing=raise_on_missing, client=client
|
|
43
|
+
)
|
|
44
|
+
return deleted >= 1
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
async def asyncio(
|
|
48
|
+
os_entity_uid: str,
|
|
49
|
+
safe: bool = False,
|
|
50
|
+
raise_on_missing: bool = False,
|
|
51
|
+
client: Client = None,
|
|
52
|
+
):
|
|
53
|
+
"""
|
|
54
|
+
# Delete asynchronously a local entity given its ID
|
|
55
|
+
|
|
56
|
+
## Arguments
|
|
57
|
+
- `os_entity_uid`: The ID of the entity to delete
|
|
58
|
+
- `safe`: Whether to raise a ValueError before removal if the entity does not exist
|
|
59
|
+
- `raise_on_missing`: Whether to raise a ConnectionError if the entity could not be deleted
|
|
60
|
+
- `client`: The Client with which to connect to Octostar. If None, the default one is used
|
|
61
|
+
|
|
62
|
+
## Returns
|
|
63
|
+
True if the entity was successfully deleted, False if no entity was deleted
|
|
64
|
+
|
|
65
|
+
## Raises
|
|
66
|
+
- `ValueError`: If the ID is not a valid entity ID (and safe is enabled)
|
|
67
|
+
- `ApiConnectionError`: If the request was unsuccessful on the server
|
|
68
|
+
- `ConnectionError`: If the entity could not be removed (and raise_on_missing is enabled)
|
|
69
|
+
"""
|
|
70
|
+
if safe:
|
|
71
|
+
uids = await query_ontology.asyncio(
|
|
72
|
+
f"SELECT `os_entity_uid` FROM `timbr`.`os_thing` WHERE `os_entity_uid`='{os_entity_uid}'",
|
|
73
|
+
client=client,
|
|
74
|
+
)
|
|
75
|
+
if not uids:
|
|
76
|
+
raise ValueError("Attempting to remove an entity which does not exist!")
|
|
77
|
+
|
|
78
|
+
deleted = await _delete_entities.asyncio(
|
|
79
|
+
[os_entity_uid], raise_on_missing=raise_on_missing, client=client
|
|
80
|
+
)
|
|
81
|
+
return deleted >= 1
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
_logger = logging.getLogger(__name__)
|
|
4
|
+
|
|
5
|
+
from ..ontology import query_ontology
|
|
6
|
+
from ...client import Client
|
|
7
|
+
from . import delete_entities as _delete_entities
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def sync(
|
|
11
|
+
os_relationship_uid: str,
|
|
12
|
+
safe: bool = False,
|
|
13
|
+
raise_on_missing: bool = False,
|
|
14
|
+
client: Client = None,
|
|
15
|
+
):
|
|
16
|
+
"""
|
|
17
|
+
# Delete a local relationship between two entities given its ID
|
|
18
|
+
|
|
19
|
+
## Arguments
|
|
20
|
+
- `os_relationship_uid`: The ID of the relationship to delete
|
|
21
|
+
- `safe`: Whether to raise a ValueError before removal if the relationship does not exist
|
|
22
|
+
- `raise_on_missing`: Whether to raise a ConnectionError if the relationship could not be deleted
|
|
23
|
+
- `client`: The Client with which to connect to Octostar. If None, the default one is used
|
|
24
|
+
|
|
25
|
+
## Returns
|
|
26
|
+
True if the relationship was successfully deleted, False if no relationship was deleted
|
|
27
|
+
|
|
28
|
+
## Raises
|
|
29
|
+
- `ValueError`: If the ID is not a valid relationship ID (and safe is enabled)
|
|
30
|
+
- `ApiConnectionError`: If the request was unsuccessful on the server
|
|
31
|
+
- `ConnectionError`: If the relationship could not be removed (and raise_on_missing is enabled)
|
|
32
|
+
"""
|
|
33
|
+
if safe:
|
|
34
|
+
uids = query_ontology.sync(
|
|
35
|
+
f"SELECT `os_entity_uid` FROM `timbr`.`os_relationship` WHERE `os_entity_uid`='{os_relationship_uid}'",
|
|
36
|
+
client=client,
|
|
37
|
+
)
|
|
38
|
+
if not uids:
|
|
39
|
+
raise ValueError("Attempting to remove an entity which does not exist!")
|
|
40
|
+
|
|
41
|
+
deleted = _delete_entities.sync(
|
|
42
|
+
[os_relationship_uid], raise_on_missing=raise_on_missing, client=client
|
|
43
|
+
)
|
|
44
|
+
return deleted >= 1
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
async def asyncio(
|
|
48
|
+
os_relationship_uid: str,
|
|
49
|
+
safe: bool = False,
|
|
50
|
+
raise_on_missing: bool = False,
|
|
51
|
+
client: Client = None,
|
|
52
|
+
):
|
|
53
|
+
"""
|
|
54
|
+
# Delete asynchronously a local relationship between two entities given its ID
|
|
55
|
+
|
|
56
|
+
## Arguments
|
|
57
|
+
(Same as sync function)
|
|
58
|
+
|
|
59
|
+
## Returns
|
|
60
|
+
True if the relationship was successfully deleted, False if no relationship was deleted
|
|
61
|
+
|
|
62
|
+
## Raises
|
|
63
|
+
- `ValueError`: If the ID is not a valid relationship ID (and safe is enabled)
|
|
64
|
+
- `ApiConnectionError`: If the request was unsuccessful on the server
|
|
65
|
+
- `ConnectionError`: If the relationship could not be removed (and raise_on_missing is enabled)
|
|
66
|
+
"""
|
|
67
|
+
if safe:
|
|
68
|
+
uids = await query_ontology.asyncio(
|
|
69
|
+
f"SELECT `os_entity_uid` FROM `timbr`.`os_relationship` WHERE `os_entity_uid`='{os_relationship_uid}'",
|
|
70
|
+
client=client,
|
|
71
|
+
)
|
|
72
|
+
if not uids:
|
|
73
|
+
raise ValueError("Attempting to remove an entity which does not exist!")
|
|
74
|
+
|
|
75
|
+
deleted = await _delete_entities.asyncio(
|
|
76
|
+
[os_relationship_uid], raise_on_missing=raise_on_missing, client=client
|
|
77
|
+
)
|
|
78
|
+
return deleted >= 1
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
_logger = logging.getLogger(__name__)
|
|
5
|
+
|
|
6
|
+
from ..ontology import query_ontology
|
|
7
|
+
from ...client import Client
|
|
8
|
+
from . import delete_entities as _delete_entities
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def sync(
|
|
12
|
+
os_relationship_uids: List[str],
|
|
13
|
+
safe: bool = False,
|
|
14
|
+
raise_on_missing: bool = False,
|
|
15
|
+
client: Client = None,
|
|
16
|
+
):
|
|
17
|
+
"""
|
|
18
|
+
# Delete a list of local relationships given their IDs
|
|
19
|
+
|
|
20
|
+
## Arguments
|
|
21
|
+
- `os_relationships_uids`: The list of IDs
|
|
22
|
+
- `safe`: Whether to raise a ValueError before removal if some relationships in the list do not exist
|
|
23
|
+
- `raise_on_missing`: Whether to raise a ConnectionError if some of the relationships could not be deleted
|
|
24
|
+
- `client`: The Client with which to connect to Octostar. If None, the default one is used
|
|
25
|
+
|
|
26
|
+
## Returns
|
|
27
|
+
The number of successfully deleted relationships
|
|
28
|
+
|
|
29
|
+
## Raises
|
|
30
|
+
- `ValueError`: If the list of IDs contain invalid entries (and safe is enabled)
|
|
31
|
+
- `ApiConnectionError`: If the request was unsuccessful on the server
|
|
32
|
+
- `ConnectionError`: If some of the relationships could not be removed (and raise_on_missing is enabled)
|
|
33
|
+
"""
|
|
34
|
+
assert len(os_relationship_uids) > 0
|
|
35
|
+
if safe:
|
|
36
|
+
uids_text = ", ".join(f"'{uid}'" for uid in os_relationship_uids)
|
|
37
|
+
uids = query_ontology.sync(
|
|
38
|
+
f"SELECT `os_entity_uid` FROM `timbr`.`os_relationship` WHERE `os_entity_uid` IN ({uids_text})",
|
|
39
|
+
client=client,
|
|
40
|
+
)
|
|
41
|
+
if len(uids or []) < len(os_relationship_uids):
|
|
42
|
+
raise ValueError(
|
|
43
|
+
"Attempting to remove a relationship which does not exist!"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
return _delete_entities.sync(
|
|
47
|
+
os_relationship_uids, raise_on_missing=raise_on_missing, client=client
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
async def asyncio(
|
|
52
|
+
os_relationship_uids: List[str],
|
|
53
|
+
safe: bool = False,
|
|
54
|
+
raise_on_missing: bool = False,
|
|
55
|
+
client: Client = None,
|
|
56
|
+
):
|
|
57
|
+
"""
|
|
58
|
+
# Delete asynchronously a list of local relationships given their IDs
|
|
59
|
+
|
|
60
|
+
## Arguments
|
|
61
|
+
(Same as sync function)
|
|
62
|
+
|
|
63
|
+
## Returns
|
|
64
|
+
The number of successfully deleted relationships
|
|
65
|
+
|
|
66
|
+
## Raises
|
|
67
|
+
- `ValueError`: If the list of IDs contain invalid entries (and safe is enabled)
|
|
68
|
+
- `ApiConnectionError`: If the request was unsuccessful on the server
|
|
69
|
+
- `ConnectionError`: If some of the relationships could not be removed (and raise_on_missing is enabled)
|
|
70
|
+
"""
|
|
71
|
+
assert len(os_relationship_uids) > 0
|
|
72
|
+
if safe:
|
|
73
|
+
uids_text = ", ".join(f"'{uid}'" for uid in os_relationship_uids)
|
|
74
|
+
uids = await query_ontology.asyncio(
|
|
75
|
+
f"SELECT `os_entity_uid` FROM `timbr`.`os_relationship` WHERE `os_entity_uid` IN ({uids_text})",
|
|
76
|
+
client=client,
|
|
77
|
+
)
|
|
78
|
+
if len(uids or []) < len(os_relationship_uids):
|
|
79
|
+
raise ValueError(
|
|
80
|
+
"Attempting to remove a relationship which does not exist!"
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
return await _delete_entities.asyncio(
|
|
84
|
+
os_relationship_uids, raise_on_missing=raise_on_missing, client=client
|
|
85
|
+
)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import httpx
|
|
3
|
+
|
|
4
|
+
_logger = logging.getLogger(__name__)
|
|
5
|
+
|
|
6
|
+
from ...client import Client, get_default_client
|
|
7
|
+
from ..commons import network_retry_strategy
|
|
8
|
+
from ..exceptions import ApiConnectionError
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
DEFAULT_TIMEOUT = 120
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _delete_api_url(client: Client, filename: str) -> str:
|
|
15
|
+
"""Build the blob delete API endpoint URL."""
|
|
16
|
+
base = client.get_base_url_v1()
|
|
17
|
+
return f"{base}/api/v1/files/delete-blob/{filename}"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def sync(
|
|
21
|
+
filename: str,
|
|
22
|
+
client: Client = None,
|
|
23
|
+
):
|
|
24
|
+
"""
|
|
25
|
+
# Delete a temporary blob from the user's temp bucket
|
|
26
|
+
|
|
27
|
+
Permanently removes a file from the authenticated user's temporary S3 bucket.
|
|
28
|
+
Use this to clean up temporary files that are no longer needed.
|
|
29
|
+
|
|
30
|
+
## Arguments
|
|
31
|
+
- `filename`: The name of the file in the temp bucket to delete
|
|
32
|
+
- `client`: The Client with which to connect to Octostar. If None, the default one is used
|
|
33
|
+
|
|
34
|
+
## Raises
|
|
35
|
+
- `ApiConnectionError`: If the deletion request failed
|
|
36
|
+
"""
|
|
37
|
+
if not client:
|
|
38
|
+
client = get_default_client()
|
|
39
|
+
|
|
40
|
+
api_url = _delete_api_url(client, filename)
|
|
41
|
+
headers = dict(client.get_headers())
|
|
42
|
+
|
|
43
|
+
response = None
|
|
44
|
+
try:
|
|
45
|
+
for attempt in network_retry_strategy():
|
|
46
|
+
with attempt:
|
|
47
|
+
with httpx.Client(timeout=DEFAULT_TIMEOUT) as http_client:
|
|
48
|
+
response = http_client.delete(api_url, headers=headers)
|
|
49
|
+
response.raise_for_status()
|
|
50
|
+
except Exception:
|
|
51
|
+
raise ApiConnectionError("delete_temporary_blob", response, client)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
async def asyncio(
|
|
55
|
+
filename: str,
|
|
56
|
+
client: Client = None,
|
|
57
|
+
):
|
|
58
|
+
"""
|
|
59
|
+
# Delete a temporary blob from the user's temp bucket (async)
|
|
60
|
+
|
|
61
|
+
Permanently removes a file from the authenticated user's temporary S3 bucket.
|
|
62
|
+
Use this to clean up temporary files that are no longer needed.
|
|
63
|
+
|
|
64
|
+
## Arguments
|
|
65
|
+
- `filename`: The name of the file in the temp bucket to delete
|
|
66
|
+
- `client`: The Client with which to connect to Octostar. If None, the default one is used
|
|
67
|
+
|
|
68
|
+
## Raises
|
|
69
|
+
- `ApiConnectionError`: If the deletion request failed
|
|
70
|
+
"""
|
|
71
|
+
if not client:
|
|
72
|
+
client = get_default_client()
|
|
73
|
+
|
|
74
|
+
api_url = _delete_api_url(client, filename)
|
|
75
|
+
headers = dict(client.get_headers())
|
|
76
|
+
|
|
77
|
+
response = None
|
|
78
|
+
try:
|
|
79
|
+
for attempt in network_retry_strategy():
|
|
80
|
+
with attempt:
|
|
81
|
+
async with httpx.AsyncClient(timeout=DEFAULT_TIMEOUT) as http_client:
|
|
82
|
+
response = await http_client.delete(api_url, headers=headers)
|
|
83
|
+
response.raise_for_status()
|
|
84
|
+
except Exception:
|
|
85
|
+
raise ApiConnectionError("delete_temporary_blob", response, client)
|