das-cli 1.1.0__py3-none-any.whl → 1.2.0__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.
Potentially problematic release.
This version of das-cli might be problematic. Click here for more details.
- das/cli.py +32 -0
- das/common/api.py +20 -0
- das/managers/download_manager.py +43 -1
- das/services/downloads.py +19 -2
- {das_cli-1.1.0.dist-info → das_cli-1.2.0.dist-info}/METADATA +1 -1
- {das_cli-1.1.0.dist-info → das_cli-1.2.0.dist-info}/RECORD +10 -10
- {das_cli-1.1.0.dist-info → das_cli-1.2.0.dist-info}/WHEEL +0 -0
- {das_cli-1.1.0.dist-info → das_cli-1.2.0.dist-info}/entry_points.txt +0 -0
- {das_cli-1.1.0.dist-info → das_cli-1.2.0.dist-info}/licenses/LICENSE +0 -0
- {das_cli-1.1.0.dist-info → das_cli-1.2.0.dist-info}/top_level.txt +0 -0
das/cli.py
CHANGED
|
@@ -992,6 +992,38 @@ def create_download_request(das_ctx, name, entry, file, from_file, output_format
|
|
|
992
992
|
except Exception as e:
|
|
993
993
|
click.secho(f"Error: {e}", fg="red")
|
|
994
994
|
|
|
995
|
+
@download.command("files")
|
|
996
|
+
@click.argument('request_id', required=True)
|
|
997
|
+
@click.option('--out', 'output_path', required=False, default='.', help='Output file path or directory (defaults to current directory)')
|
|
998
|
+
@click.option('--force', is_flag=True, help='Overwrite existing file if present')
|
|
999
|
+
@pass_das_context
|
|
1000
|
+
def download_files(das_ctx, request_id, output_path, force):
|
|
1001
|
+
"""
|
|
1002
|
+
Download the completed bundle for a download request and save it to disk.
|
|
1003
|
+
|
|
1004
|
+
Examples:
|
|
1005
|
+
|
|
1006
|
+
\b
|
|
1007
|
+
# Save into current directory with server-provided filename
|
|
1008
|
+
das download files 6b0e68e6-00cd-43a7-9c51-d56c9c091123
|
|
1009
|
+
|
|
1010
|
+
\b
|
|
1011
|
+
# Save to a specific folder
|
|
1012
|
+
das download files 6b0e68e6-00cd-43a7-9c51-d56c9c091123 --out C:\\Downloads
|
|
1013
|
+
|
|
1014
|
+
\b
|
|
1015
|
+
# Save to an explicit filename, overwriting if exists
|
|
1016
|
+
das download files 6b0e68e6-00cd-43a7-9c51-d56c9c091123 --out C:\\Downloads\\bundle.zip --force
|
|
1017
|
+
"""
|
|
1018
|
+
try:
|
|
1019
|
+
das_ctx.get_client()
|
|
1020
|
+
saved_path = das_ctx.download_manager.save_download(request_id=request_id, output_path=output_path, overwrite=force)
|
|
1021
|
+
click.secho(f"✓ Download saved to: {saved_path}", fg="green")
|
|
1022
|
+
except FileExistsError as e:
|
|
1023
|
+
click.secho(str(e), fg="yellow")
|
|
1024
|
+
except Exception as e:
|
|
1025
|
+
click.secho(f"Error: {e}", fg="red")
|
|
1026
|
+
|
|
995
1027
|
@download.command("delete-request")
|
|
996
1028
|
@click.argument('request_id', required=True)
|
|
997
1029
|
@pass_das_context
|
das/common/api.py
CHANGED
|
@@ -27,6 +27,26 @@ def get_data(url, headers=None, params=None):
|
|
|
27
27
|
print(f"Error fetching API data: {e}")
|
|
28
28
|
return {"error": str(e)}
|
|
29
29
|
|
|
30
|
+
def get_binary_response(url, headers=None, params=None, stream=True):
|
|
31
|
+
"""
|
|
32
|
+
Perform a GET request expected to return binary content.
|
|
33
|
+
|
|
34
|
+
Returns the raw requests.Response so callers can inspect headers
|
|
35
|
+
and stream content to disk.
|
|
36
|
+
"""
|
|
37
|
+
try:
|
|
38
|
+
response = requests.get(
|
|
39
|
+
url,
|
|
40
|
+
headers=headers,
|
|
41
|
+
params=params,
|
|
42
|
+
verify=load_verify_ssl(),
|
|
43
|
+
stream=stream,
|
|
44
|
+
)
|
|
45
|
+
response.raise_for_status()
|
|
46
|
+
return response
|
|
47
|
+
except requests.RequestException as e:
|
|
48
|
+
return {"error": str(e)}
|
|
49
|
+
|
|
30
50
|
def post_data(url, headers=None, data=None):
|
|
31
51
|
"""
|
|
32
52
|
Send data to a REST API endpoint.
|
das/managers/download_manager.py
CHANGED
|
@@ -90,4 +90,46 @@ class DownloadManager:
|
|
|
90
90
|
|
|
91
91
|
def get_my_requests(self):
|
|
92
92
|
"""Get all download requests for the current user."""
|
|
93
|
-
return self.download_request_service.get_my_requests()
|
|
93
|
+
return self.download_request_service.get_my_requests()
|
|
94
|
+
|
|
95
|
+
def download_files(self, request_id: str):
|
|
96
|
+
"""Return streaming response for files of a download request."""
|
|
97
|
+
return self.download_request_service.download_files(request_id)
|
|
98
|
+
|
|
99
|
+
def save_download(self, request_id: str, output_path: str, overwrite: bool = False) -> str:
|
|
100
|
+
"""
|
|
101
|
+
Download and save the request bundle to disk.
|
|
102
|
+
|
|
103
|
+
Returns the path to the saved file.
|
|
104
|
+
"""
|
|
105
|
+
import os
|
|
106
|
+
|
|
107
|
+
resp = self.download_files(request_id)
|
|
108
|
+
# If an error structure was returned from lower layer
|
|
109
|
+
if isinstance(resp, dict) and resp.get('error'):
|
|
110
|
+
raise ValueError(resp['error'])
|
|
111
|
+
|
|
112
|
+
# Determine filename from headers if available
|
|
113
|
+
filename = f"download_{request_id}.zip"
|
|
114
|
+
try:
|
|
115
|
+
cd = resp.headers.get('Content-Disposition') if hasattr(resp, 'headers') else None
|
|
116
|
+
if cd and 'filename=' in cd:
|
|
117
|
+
filename = cd.split('filename=')[-1].strip('"')
|
|
118
|
+
except Exception:
|
|
119
|
+
pass
|
|
120
|
+
|
|
121
|
+
# If output_path is a directory, join with filename
|
|
122
|
+
target_path = output_path
|
|
123
|
+
if os.path.isdir(output_path) or output_path.endswith(os.path.sep):
|
|
124
|
+
target_path = os.path.join(output_path, filename)
|
|
125
|
+
|
|
126
|
+
if os.path.exists(target_path) and not overwrite:
|
|
127
|
+
raise FileExistsError(f"File already exists: {target_path}. Use overwrite to replace.")
|
|
128
|
+
|
|
129
|
+
# Stream to disk
|
|
130
|
+
with open(target_path, 'wb') as f:
|
|
131
|
+
for chunk in resp.iter_content(chunk_size=8192):
|
|
132
|
+
if chunk:
|
|
133
|
+
f.write(chunk)
|
|
134
|
+
|
|
135
|
+
return target_path
|
das/services/downloads.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
from das.common.api import post_data, get_data
|
|
1
|
+
from das.common.api import post_data, get_data, get_binary_response
|
|
2
2
|
from das.common.config import load_token
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class DownloadRequestService:
|
|
6
6
|
def __init__(self, base_url):
|
|
7
7
|
self.base_url = f"{base_url}/api/services/app/DownloadRequest"
|
|
8
|
+
self.download_files_url = f"{base_url}/File/DownloadRequestSet"
|
|
8
9
|
|
|
9
10
|
def create(self, request_data: list[dict]):
|
|
10
11
|
"""Create a new download request."""
|
|
@@ -81,4 +82,20 @@ class DownloadRequestService:
|
|
|
81
82
|
error_msg = None
|
|
82
83
|
if isinstance(response, dict):
|
|
83
84
|
error_msg = response.get('error') or response.get('message')
|
|
84
|
-
raise ValueError(error_msg or 'Failed to fetch download requests')
|
|
85
|
+
raise ValueError(error_msg or 'Failed to fetch download requests')
|
|
86
|
+
|
|
87
|
+
def download_files(self, request_id: str):
|
|
88
|
+
"""Return a streaming HTTP response for the download bundle of a request."""
|
|
89
|
+
token = load_token()
|
|
90
|
+
|
|
91
|
+
if (token is None or token == ""):
|
|
92
|
+
raise ValueError("Authorization token is required")
|
|
93
|
+
|
|
94
|
+
headers = {
|
|
95
|
+
"Authorization": f"Bearer {token}"
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
url = f"{self.download_files_url}?requestId={request_id}"
|
|
99
|
+
|
|
100
|
+
response = get_binary_response(url, headers=headers, params=None, stream=True)
|
|
101
|
+
return response
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
das/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
das/app.py,sha256=kKxN4Vn84SA5Ph3zY13avMG2vrUp-ffpdDkhwYR9Bho,1475
|
|
3
|
-
das/cli.py,sha256=
|
|
3
|
+
das/cli.py,sha256=f09aWaCW26vU3lBJjdidg6YtevxylWgHR8blu6CBd_k,49834
|
|
4
4
|
das/ai/plugins/dasai.py,sha256=R0X0Vey_GOAtWoqcloB-NATZFtXB_l5b9dfPXocNIbI,2165
|
|
5
5
|
das/ai/plugins/entries/entries_plugin.py,sha256=Dhv6PrguQj5mzxBW6DlCzkmwucszazLQfzwlp9EhIGk,608
|
|
6
6
|
das/authentication/auth.py,sha256=DTtH66Ft6nuuMe7EYvrr3GqGVEGGxE7GmD2fO7vRv4s,1501
|
|
7
7
|
das/authentication/secure_input.py,sha256=P-NpbFeHrp2uIOMqip55cGn_NqqpswhnknAF1t7c2_U,1911
|
|
8
|
-
das/common/api.py,sha256=
|
|
8
|
+
das/common/api.py,sha256=GNY1nF5B8JgFDAGifC2jR2ZTtKt4GLd7W20ARky4wcY,4501
|
|
9
9
|
das/common/config.py,sha256=VQi_tJ7hvIa--gvx9VCBkfVI9p0ptOvifIu08tc8kEs,6127
|
|
10
10
|
das/common/entry_fields_constants.py,sha256=5Yh4Ujt70HEF-FsnwVBPBm3DB3HHzQWSWR-9Upt7C5I,93
|
|
11
11
|
das/common/enums.py,sha256=jS0frv6717duG_wZNockXMTZ-VfsGu_f8_-lgYGnrcY,1745
|
|
12
12
|
das/common/file_utils.py,sha256=-zePjYsj8iRpQssVQMHDK3Mh5q8FooKJCUCKCXKS6_Y,7006
|
|
13
13
|
das/managers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
14
|
das/managers/digital_objects_manager.py,sha256=v7VAYfKoDpmWJGVgpVoSyk6hqGMiQJeOX5rgm65xE5U,3677
|
|
15
|
-
das/managers/download_manager.py,sha256=
|
|
15
|
+
das/managers/download_manager.py,sha256=bZuRX5yoKC_n00Tbjn_aRHgHLeq6SjI0TqDqgjttOQU,5431
|
|
16
16
|
das/managers/entries_manager.py,sha256=Kc_PN71Bp7VICrxoP9MiDCrUzR7OdUXfX5puDDxtm08,19015
|
|
17
17
|
das/managers/search_manager.py,sha256=vXf0JmK5oW-xEGUdDnppfc1-6HdH1hfiZR7L2bCz9u0,4263
|
|
18
18
|
das/services/attributes.py,sha256=78E9f1wNZYxG9Hg5HfX_h1CFmACaMjwD2Y6Ilb7PJGY,2616
|
|
19
19
|
das/services/cache.py,sha256=g-vY51gqGV_1Vpza476PkMqGpuDNo1NbTwQWIIsvO0s,1932
|
|
20
20
|
das/services/digital_objects.py,sha256=ww1KHVLNmm_ffzgqP4Jt4wCbHMVfhD2FJWahlSPFaes,4935
|
|
21
|
-
das/services/downloads.py,sha256=
|
|
21
|
+
das/services/downloads.py,sha256=cn2eoiKEDRcINlzoLgw6mpN3VVLBBiccdFyuCO7TB2I,3709
|
|
22
22
|
das/services/entries.py,sha256=Uspl7LZcNWEnr7ct5_Kn31jMjrkSKV7UXzrN6nb3HF0,4966
|
|
23
23
|
das/services/entry_fields.py,sha256=x2wUDkKNduj9pf4s56hRo0UW-eBhipkU9gFMEjFw5DA,1290
|
|
24
24
|
das/services/hangfire.py,sha256=hidmVP9yb4znzBaJJRyKawYx7oYaBv5OVL-t0BhvN_A,818
|
|
25
25
|
das/services/search.py,sha256=3X_KPb9fs024FhxoTr4j-xY5ymm5rvvzlekxuh8tLdg,1374
|
|
26
26
|
das/services/users.py,sha256=iNijO2UPIEtcpPy8Tkemdxxym9rYLCUyckQHIQj68W0,795
|
|
27
|
-
das_cli-1.
|
|
28
|
-
das_cli-1.
|
|
29
|
-
das_cli-1.
|
|
30
|
-
das_cli-1.
|
|
31
|
-
das_cli-1.
|
|
32
|
-
das_cli-1.
|
|
27
|
+
das_cli-1.2.0.dist-info/licenses/LICENSE,sha256=4EDhysVgQWBlzo0rdUl_k89s-iVfgCcSa1gUx1TM1vA,1124
|
|
28
|
+
das_cli-1.2.0.dist-info/METADATA,sha256=mxD9Zy0gUaaqTq4bMkIbqHt594Fs4S3Oi-zVxaLXDIc,11375
|
|
29
|
+
das_cli-1.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
30
|
+
das_cli-1.2.0.dist-info/entry_points.txt,sha256=ZrdMae7NcvogQhzM1zun8E8n_QwYq-LpZvoJCr2_I4g,36
|
|
31
|
+
das_cli-1.2.0.dist-info/top_level.txt,sha256=OJsPEeJyJ2rJlpEn2DTPgbMSvYG-6FeD13_m5qLpw3E,4
|
|
32
|
+
das_cli-1.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|