das-cli 1.2.5__py3-none-any.whl → 1.2.6__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.
das/common/file_utils.py CHANGED
@@ -67,6 +67,9 @@ def load_csv_file(file_path: str) -> List[Dict[str, Any]]:
67
67
 
68
68
  if not headers:
69
69
  raise ValueError("CSV file is empty or has no headers")
70
+
71
+ # Strip leading/trailing whitespace from column headers
72
+ headers = [h.strip() for h in headers]
70
73
 
71
74
  result = []
72
75
  for row in reader:
@@ -172,7 +172,7 @@ class EntryManager:
172
172
 
173
173
  return self.entry_service.create(attribute_id=attribute_id, entry=new_entry)
174
174
 
175
- def update(self, attribute: str, code: str = None, entry: dict = None, entries: list = None) -> list:
175
+ def update(self, id: str = None, code: str = None, entry: dict = None, entries: list = None) -> list:
176
176
  """
177
177
  Update one or more existing entries.
178
178
 
@@ -180,7 +180,7 @@ class EntryManager:
180
180
  If 'entries' is provided, updates multiple entries based on the code in each entry.
181
181
 
182
182
  Args:
183
- attribute (str): The attribute name
183
+ id (str, optional): The entry ID for single entry update
184
184
  code (str, optional): The entry code for single entry update
185
185
  entry (dict, optional): The entry data for single entry update
186
186
  entries (list, optional): List of entry data for multiple updates
@@ -206,34 +206,40 @@ class EntryManager:
206
206
 
207
207
  # Each entry must have a Code field
208
208
  entry_code = next((entry_data.get(key) for key in entry_data if key.lower() == 'code'), None)
209
+ entry_id = next((entry_data.get(key) for key in entry_data if key.lower() == 'id'), None)
209
210
  if not entry_code:
210
- raise ValueError(f"Entry code is missing in entry data: {entry_data}")
211
+ entry_data['code'] = code
212
+ if not entry_id:
213
+ entry_data['id'] = id
211
214
 
212
215
  try:
213
- result = self._update_single_entry(attribute, entry_code, entry_data)
216
+ result = self._update_single_entry(id=id, code=code, entry=entry_data)
214
217
  results.append({"code": entry_code, "id": result, "status": "success"})
215
218
  except Exception as e:
216
219
  results.append({"code": entry_code, "error": str(e), "status": "error"})
217
220
 
218
221
  return results
219
222
 
220
- elif code and entry:
223
+ elif (code or id) and entry:
221
224
  # Single entry update
222
- result = self._update_single_entry(attribute, code, entry)
225
+ result = self._update_single_entry(id=id, code=code, entry=entry)
223
226
  return [{"code": code, "id": result, "status": "success"}]
224
227
 
225
228
  else:
226
- raise ValueError("Either 'code' and 'entry' or 'entries' must be provided")
229
+ raise ValueError("Either 'id', 'code' and 'entry' or 'entries' must be provided")
227
230
 
228
- def _update_single_entry(self, attribute: str, code: str, entry: dict) -> str:
231
+ def _update_single_entry(self, id: str = None, code: str = None, entry: dict = None) -> str:
229
232
  """Internal method to update a single entry."""
230
- if not code:
231
- raise ValueError("Entry code is required")
232
-
233
- if not entry or not isinstance(entry, dict):
234
- raise ValueError("Entry data must be a non-empty dictionary")
235
-
236
- existing_entry_response = self.entry_service.get_entry(code=code)
233
+ if not id and not code:
234
+ raise ValueError("Entry ID or code is required")
235
+ if id:
236
+ if not entry:
237
+ raise ValueError("Entry data is required")
238
+ existing_entry_response = self.entry_service.get(id=id)
239
+ elif code:
240
+ existing_entry_response = self.entry_service.get(code=code)
241
+ else:
242
+ raise ValueError("Entry ID or code is required")
237
243
 
238
244
  if not existing_entry_response or not isinstance(existing_entry_response, dict):
239
245
  raise ValueError(f"Invalid existing entry response: {existing_entry_response}")
das/services/downloads.py CHANGED
@@ -1,101 +1,101 @@
1
- from das.common.api import post_data, get_data, get_binary_response
2
- from das.common.config import load_token
3
-
4
-
5
- class DownloadRequestService:
6
- def __init__(self, base_url):
7
- self.base_url = f"{base_url}/api/services/app/DownloadRequest"
8
- self.download_files_url = f"{base_url}/File/DownloadRequestSet"
9
-
10
- def create(self, request_data: list[dict]):
11
- """Create a new download request."""
12
- token = load_token()
13
-
14
- if (token is None or token == ""):
15
- raise ValueError("Authorization token is required")
16
-
17
- headers = {
18
- "Authorization": f"Bearer {token}",
19
- "Content-Type": "application/json"
20
- }
21
-
22
- url = f"{self.base_url}/Create"
23
-
24
- response = post_data(url, data=request_data, headers=headers)
25
-
26
- if response.get('success') == True:
27
- return response.get('result')
28
- else:
29
- raise ValueError(response.get('error'))
30
-
31
- def delete(self, request_id: str):
32
- """Delete a download request by ID."""
33
-
34
- #check if request_id is valid uuid
35
- if not isinstance(request_id, str) or len(request_id) != 36:
36
- raise ValueError("Invalid request ID")
37
-
38
- token = load_token()
39
-
40
- if (token is None or token == ""):
41
- raise ValueError("Authorization token is required")
42
-
43
- headers = {
44
- "Authorization": f"Bearer {token}",
45
- "Content-Type": "application/json"
46
- }
47
-
48
- url = f"{self.base_url}/Delete?downloadRequestId={request_id}"
49
-
50
- response = post_data(url, data={}, headers=headers)
51
-
52
- if response.get('success') == True:
53
- return response.get('result')
54
- else:
55
- raise ValueError(response.get('error'))
56
-
57
- def get_my_requests(self):
58
- """Get all download requests for the current user."""
59
- token = load_token()
60
-
61
- if (token is None or token == ""):
62
- raise ValueError("Authorization token is required")
63
-
64
- headers = {
65
- "Authorization": f"Bearer {token}"
66
- }
67
-
68
- url = f"{self.base_url}/GetMyRequests"
69
- response = get_data(url, headers=headers)
70
-
71
- # Expected API response shape:
72
- # { success: true, result: { totalCount: number, items: [...] }, ... }
73
- if isinstance(response, dict) and response.get('success') is True:
74
- return response.get('result')
75
- # Some backends might already return the result without 'success'
76
- if isinstance(response, dict) and 'result' in response and 'success' not in response:
77
- return response.get('result')
78
- # If the API directly returns the payload (result), pass it through
79
- if isinstance(response, dict) and 'items' in response and 'totalCount' in response:
80
- return response
81
- # Otherwise raise a meaningful error
82
- error_msg = None
83
- if isinstance(response, dict):
84
- error_msg = response.get('error') or response.get('message')
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)
1
+ from das.common.api import post_data, get_data, get_binary_response
2
+ from das.common.config import load_token
3
+
4
+
5
+ class DownloadRequestService:
6
+ def __init__(self, base_url):
7
+ self.base_url = f"{base_url}/api/services/app/DownloadRequest"
8
+ self.download_files_url = f"{base_url}/File/DownloadRequestSet"
9
+
10
+ def create(self, request_data: list[dict]):
11
+ """Create a new download request."""
12
+ token = load_token()
13
+
14
+ if (token is None or token == ""):
15
+ raise ValueError("Authorization token is required")
16
+
17
+ headers = {
18
+ "Authorization": f"Bearer {token}",
19
+ "Content-Type": "application/json"
20
+ }
21
+
22
+ url = f"{self.base_url}/Create"
23
+
24
+ response = post_data(url, data=request_data, headers=headers)
25
+
26
+ if response.get('success') == True:
27
+ return response.get('result')
28
+ else:
29
+ raise ValueError(response.get('error'))
30
+
31
+ def delete(self, request_id: str):
32
+ """Delete a download request by ID."""
33
+
34
+ #check if request_id is valid uuid
35
+ if not isinstance(request_id, str) or len(request_id) != 36:
36
+ raise ValueError("Invalid request ID")
37
+
38
+ token = load_token()
39
+
40
+ if (token is None or token == ""):
41
+ raise ValueError("Authorization token is required")
42
+
43
+ headers = {
44
+ "Authorization": f"Bearer {token}",
45
+ "Content-Type": "application/json"
46
+ }
47
+
48
+ url = f"{self.base_url}/Delete?downloadRequestId={request_id}"
49
+
50
+ response = post_data(url, data={}, headers=headers)
51
+
52
+ if response.get('success') == True:
53
+ return response.get('result')
54
+ else:
55
+ raise ValueError(response.get('error'))
56
+
57
+ def get_my_requests(self):
58
+ """Get all download requests for the current user."""
59
+ token = load_token()
60
+
61
+ if (token is None or token == ""):
62
+ raise ValueError("Authorization token is required")
63
+
64
+ headers = {
65
+ "Authorization": f"Bearer {token}"
66
+ }
67
+
68
+ url = f"{self.base_url}/GetMyRequests"
69
+ response = get_data(url, headers=headers)
70
+
71
+ # Expected API response shape:
72
+ # { success: true, result: { totalCount: number, items: [...] }, ... }
73
+ if isinstance(response, dict) and response.get('success') is True:
74
+ return response.get('result')
75
+ # Some backends might already return the result without 'success'
76
+ if isinstance(response, dict) and 'result' in response and 'success' not in response:
77
+ return response.get('result')
78
+ # If the API directly returns the payload (result), pass it through
79
+ if isinstance(response, dict) and 'items' in response and 'totalCount' in response:
80
+ return response
81
+ # Otherwise raise a meaningful error
82
+ error_msg = None
83
+ if isinstance(response, dict):
84
+ error_msg = response.get('error') or response.get('message')
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
101
  return response
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: das-cli
3
- Version: 1.2.5
3
+ Version: 1.2.6
4
4
  Summary: DAS api client.
5
5
  Author: Royal Netherlands Institute for Sea Research
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  das/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  das/app.py,sha256=kKxN4Vn84SA5Ph3zY13avMG2vrUp-ffpdDkhwYR9Bho,1475
3
- das/cli.py,sha256=LBZMuI3xFuWT3uUK3zvevgJDHnG4QTm1UqOQAa2r_gM,49228
3
+ das/cli.py,sha256=lh6RGqxACR4OOS7wrkhfD2yXli-Z7dsrch1_HNF05LM,51264
4
4
  das/ai/plugins/dasai.py,sha256=1P-0q4ReAnmJxliGAPMxR1aij9RWKxyTIHJzWTwLZLo,2459
5
5
  das/ai/plugins/entries/entries_plugin.py,sha256=Dhv6PrguQj5mzxBW6DlCzkmwucszazLQfzwlp9EhIGk,608
6
6
  das/authentication/auth.py,sha256=DTtH66Ft6nuuMe7EYvrr3GqGVEGGxE7GmD2fO7vRv4s,1501
@@ -9,24 +9,24 @@ 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
- das/common/file_utils.py,sha256=-zePjYsj8iRpQssVQMHDK3Mh5q8FooKJCUCKCXKS6_Y,7006
12
+ das/common/file_utils.py,sha256=Mb1uV9OAHle4zPSQFrythsU_8fzYV5grjgc1p9cmeA4,7129
13
13
  das/managers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  das/managers/digital_objects_manager.py,sha256=v7VAYfKoDpmWJGVgpVoSyk6hqGMiQJeOX5rgm65xE5U,3677
15
15
  das/managers/download_manager.py,sha256=bZuRX5yoKC_n00Tbjn_aRHgHLeq6SjI0TqDqgjttOQU,5431
16
- das/managers/entries_manager.py,sha256=UVJdAjLfqPcMYIuOcFH51jhlhd-Y_qHy2u1LDvyCi3E,20523
16
+ das/managers/entries_manager.py,sha256=UEl4iI-W4OuIxYTIKVCckXOTe1pvPVoKluMrT-EcLxY,20873
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=gauyQUhu4TmClLbnBf1N9k86c0PWm8ZlMIvxoE5cOB8,3609
21
+ das/services/downloads.py,sha256=cn2eoiKEDRcINlzoLgw6mpN3VVLBBiccdFyuCO7TB2I,3709
22
22
  das/services/entries.py,sha256=Dzvzx4wOljfumjBBg4sboXmgDTQf3FNbTQp-sl9hAn0,5755
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.2.5.dist-info/licenses/LICENSE,sha256=4EDhysVgQWBlzo0rdUl_k89s-iVfgCcSa1gUx1TM1vA,1124
28
- das_cli-1.2.5.dist-info/METADATA,sha256=GbKacAx0MU0EmgHy-rSQTgvTrnunAoh0sFyM5yzLfRs,26209
29
- das_cli-1.2.5.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
30
- das_cli-1.2.5.dist-info/entry_points.txt,sha256=ZrdMae7NcvogQhzM1zun8E8n_QwYq-LpZvoJCr2_I4g,36
31
- das_cli-1.2.5.dist-info/top_level.txt,sha256=OJsPEeJyJ2rJlpEn2DTPgbMSvYG-6FeD13_m5qLpw3E,4
32
- das_cli-1.2.5.dist-info/RECORD,,
27
+ das_cli-1.2.6.dist-info/licenses/LICENSE,sha256=4EDhysVgQWBlzo0rdUl_k89s-iVfgCcSa1gUx1TM1vA,1124
28
+ das_cli-1.2.6.dist-info/METADATA,sha256=u4cqs0vje7GcJSFi9OX-9c_PIkSCVU0z-Ez2beawnOA,26209
29
+ das_cli-1.2.6.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
30
+ das_cli-1.2.6.dist-info/entry_points.txt,sha256=ZrdMae7NcvogQhzM1zun8E8n_QwYq-LpZvoJCr2_I4g,36
31
+ das_cli-1.2.6.dist-info/top_level.txt,sha256=OJsPEeJyJ2rJlpEn2DTPgbMSvYG-6FeD13_m5qLpw3E,4
32
+ das_cli-1.2.6.dist-info/RECORD,,