Skip to content

Commit e16ff76

Browse files
committed
feat: batch deletions to allow cancellation before execution
1 parent ef3e0aa commit e16ff76

File tree

2 files changed

+105
-23
lines changed

2 files changed

+105
-23
lines changed

databusclient/api/delete.py

Lines changed: 96 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,39 @@
99
)
1010

1111

12+
class DeleteQueue:
13+
"""
14+
A queue to manage multiple Databus resource deletions.
15+
Allows adding multiple databus URIs to a queue and executing their deletion in batch.
16+
"""
17+
18+
def __init__(self, databus_key: str):
19+
self.databus_key = databus_key
20+
self.queue: set[str] = set()
21+
22+
def add_uri(self, databusURI: str):
23+
self.queue.add(databusURI)
24+
25+
def add_uris(self, databusURIs: List[str]):
26+
for uri in databusURIs:
27+
self.queue.add(uri)
28+
29+
def is_empty(self) -> bool:
30+
return len(self.queue) == 0
31+
32+
def is_not_empty(self) -> bool:
33+
return len(self.queue) > 0
34+
35+
def execute(self):
36+
for uri in self.queue:
37+
print(f"[DELETE] {uri}")
38+
_delete_resource(
39+
uri,
40+
self.databus_key,
41+
force=True,
42+
)
43+
44+
1245
def _confirm_delete(databusURI: str) -> str:
1346
"""
1447
Confirm deletion of a Databus resource with the user.
@@ -44,7 +77,11 @@ def _confirm_delete(databusURI: str) -> str:
4477

4578

4679
def _delete_resource(
47-
databusURI: str, databus_key: str, dry_run: bool = False, force: bool = False
80+
databusURI: str,
81+
databus_key: str,
82+
dry_run: bool = False,
83+
force: bool = False,
84+
queue: DeleteQueue = None,
4885
):
4986
"""
5087
Delete a single Databus resource (version, artifact, group).
@@ -57,6 +94,7 @@ def _delete_resource(
5794
- databus_key: Databus API key to authenticate the deletion request
5895
- dry_run: If True, do not perform the deletion but only print what would be deleted
5996
- force: If True, skip confirmation prompt and proceed with deletion
97+
- queue: If queue is provided, add the URI to the queue instead of deleting immediately
6098
"""
6199

62100
# Confirm the deletion request, skip the request or cancel deletion process
@@ -71,12 +109,15 @@ def _delete_resource(
71109
if databus_key is None:
72110
raise ValueError("Databus API key must be provided for deletion")
73111

74-
headers = {"accept": "*/*", "X-API-KEY": databus_key}
75-
76112
if dry_run:
77113
print(f"[DRY RUN] Would delete: {databusURI}")
78114
return
79115

116+
if queue is not None:
117+
queue.add_uri(databusURI)
118+
return
119+
120+
headers = {"accept": "*/*", "X-API-KEY": databus_key}
80121
response = requests.delete(databusURI, headers=headers, timeout=30)
81122

82123
if response.status_code in (200, 204):
@@ -88,21 +129,34 @@ def _delete_resource(
88129

89130

90131
def _delete_list(
91-
databusURIs: List[str], databus_key: str, dry_run: bool = False, force: bool = False
132+
databusURIs: List[str],
133+
databus_key: str,
134+
dry_run: bool = False,
135+
force: bool = False,
136+
queue: DeleteQueue = None,
92137
):
93138
"""
94139
Delete a list of Databus resources.
95140
96141
Parameters:
97142
- databusURIs: List of full databus URIs of the resources to delete
98143
- databus_key: Databus API key to authenticate the deletion requests
144+
- dry_run: If True, do not perform the deletion but only print what would be deleted
145+
- force: If True, skip confirmation prompt and proceed with deletion
146+
- queue: If queue is provided, add the URIs to the queue instead of deleting immediately
99147
"""
100148
for databusURI in databusURIs:
101-
_delete_resource(databusURI, databus_key, dry_run=dry_run, force=force)
149+
_delete_resource(
150+
databusURI, databus_key, dry_run=dry_run, force=force, queue=queue
151+
)
102152

103153

104154
def _delete_artifact(
105-
databusURI: str, databus_key: str, dry_run: bool = False, force: bool = False
155+
databusURI: str,
156+
databus_key: str,
157+
dry_run: bool = False,
158+
force: bool = False,
159+
queue: DeleteQueue = None,
106160
):
107161
"""
108162
Delete an artifact and all its versions.
@@ -114,6 +168,8 @@ def _delete_artifact(
114168
- databusURI: The full databus URI of the artifact to delete
115169
- databus_key: Databus API key to authenticate the deletion requests
116170
- dry_run: If True, do not perform the deletion but only print what would be deleted
171+
- force: If True, skip confirmation prompt and proceed with deletion
172+
- queue: If queue is provided, add the URI to the queue instead of deleting immediately
117173
"""
118174
artifact_body = fetch_databus_jsonld(databusURI, databus_key)
119175

@@ -134,14 +190,20 @@ def _delete_artifact(
134190
print(f"No version URIs found in artifact JSON-LD for: {databusURI}")
135191
else:
136192
# Delete all versions
137-
_delete_list(version_uris, databus_key, dry_run=dry_run, force=force)
193+
_delete_list(
194+
version_uris, databus_key, dry_run=dry_run, force=force, queue=queue
195+
)
138196

139197
# Finally, delete the artifact itself
140-
_delete_resource(databusURI, databus_key, dry_run=dry_run, force=force)
198+
_delete_resource(databusURI, databus_key, dry_run=dry_run, force=force, queue=queue)
141199

142200

143201
def _delete_group(
144-
databusURI: str, databus_key: str, dry_run: bool = False, force: bool = False
202+
databusURI: str,
203+
databus_key: str,
204+
dry_run: bool = False,
205+
force: bool = False,
206+
queue: DeleteQueue = None,
145207
):
146208
"""
147209
Delete a group and all its artifacts and versions.
@@ -153,6 +215,8 @@ def _delete_group(
153215
- databusURI: The full databus URI of the group to delete
154216
- databus_key: Databus API key to authenticate the deletion requests
155217
- dry_run: If True, do not perform the deletion but only print what would be deleted
218+
- force: If True, skip confirmation prompt and proceed with deletion
219+
- queue: If queue is provided, add the URI to the queue instead of deleting immediately
156220
"""
157221
group_body = fetch_databus_jsonld(databusURI, databus_key)
158222

@@ -170,10 +234,12 @@ def _delete_group(
170234

171235
# Delete all artifacts (which deletes their versions)
172236
for artifact_uri in artifact_uris:
173-
_delete_artifact(artifact_uri, databus_key, dry_run=dry_run, force=force)
237+
_delete_artifact(
238+
artifact_uri, databus_key, dry_run=dry_run, force=force, queue=queue
239+
)
174240

175241
# Finally, delete the group itself
176-
_delete_resource(databusURI, databus_key, dry_run=dry_run, force=force)
242+
_delete_resource(databusURI, databus_key, dry_run=dry_run, force=force, queue=queue)
177243

178244

179245
def delete(databusURIs: List[str], databus_key: str, dry_run: bool, force: bool):
@@ -190,25 +256,39 @@ def delete(databusURIs: List[str], databus_key: str, dry_run: bool, force: bool)
190256
- force: If True, skip confirmation prompt and proceed with deletion
191257
"""
192258

259+
queue = DeleteQueue(databus_key)
260+
193261
for databusURI in databusURIs:
194262
_host, _account, group, artifact, version, file = (
195263
get_databus_id_parts_from_file_url(databusURI)
196264
)
197265

198266
if group == "collections" and artifact is not None:
199267
print(f"Deleting collection: {databusURI}")
200-
_delete_resource(databusURI, databus_key, dry_run=dry_run, force=force)
268+
_delete_resource(
269+
databusURI, databus_key, dry_run=dry_run, force=force, queue=queue
270+
)
201271
elif file is not None:
202272
print(f"Deleting file is not supported via API: {databusURI}")
203-
continue # skip file deletions
204273
elif version is not None:
205274
print(f"Deleting version: {databusURI}")
206-
_delete_resource(databusURI, databus_key, dry_run=dry_run, force=force)
275+
_delete_resource(
276+
databusURI, databus_key, dry_run=dry_run, force=force, queue=queue
277+
)
207278
elif artifact is not None:
208279
print(f"Deleting artifact and all its versions: {databusURI}")
209-
_delete_artifact(databusURI, databus_key, dry_run=dry_run, force=force)
280+
_delete_artifact(
281+
databusURI, databus_key, dry_run=dry_run, force=force, queue=queue
282+
)
210283
elif group is not None and group != "collections":
211284
print(f"Deleting group and all its artifacts and versions: {databusURI}")
212-
_delete_group(databusURI, databus_key, dry_run=dry_run, force=force)
285+
_delete_group(
286+
databusURI, databus_key, dry_run=dry_run, force=force, queue=queue
287+
)
213288
else:
214289
print(f"Deleting {databusURI} is not supported.")
290+
291+
# Execute queued deletions
292+
if queue.is_not_empty():
293+
print("\nExecuting queued deletions...")
294+
queue.execute()

databusclient/api/download.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,15 @@ def _download_file(
7575
print("Redirects url: ", url)
7676

7777
# --- 2. Try direct GET to redirected URL ---
78-
headers["Accept-Encoding"] = "identity" # disable gzip to get correct content-length
79-
response = requests.get(url, headers=headers, stream=True, allow_redirects=True, timeout=30)
78+
headers["Accept-Encoding"] = (
79+
"identity" # disable gzip to get correct content-length
80+
)
81+
response = requests.get(
82+
url, headers=headers, stream=True, allow_redirects=True, timeout=30
83+
)
8084
www = response.headers.get(
8185
"WWW-Authenticate", ""
82-
) # Check if authentication is required
86+
) # Check if authentication is required
8387

8488
# --- 3. If redirected to authentication 401 Unauthorized, get Vault token and retry ---
8589
if response.status_code == 401 and "bearer" in www.lower():
@@ -419,9 +423,7 @@ def _get_databus_versions_of_artifact(
419423
f"Unexpected type for 'databus:hasVersion': {type(versions).__name__}"
420424
)
421425

422-
version_urls = [
423-
v["@id"] for v in versions if isinstance(v, dict) and "@id" in v
424-
]
426+
version_urls = [v["@id"] for v in versions if isinstance(v, dict) and "@id" in v]
425427

426428
if not version_urls:
427429
raise ValueError("No versions found in artifact JSON-LD")
@@ -446,7 +448,7 @@ def _get_file_download_urls_from_artifact_jsonld(json_str: str) -> List[str]:
446448
"""
447449

448450
databusIdUrl: List[str] = []
449-
451+
450452
json_dict = json.loads(json_str)
451453
graph = json_dict.get("@graph", [])
452454
for node in graph:

0 commit comments

Comments
 (0)