das-cli 1.2.4__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/cli.py CHANGED
@@ -290,38 +290,39 @@ def entry():
290
290
  pass
291
291
 
292
292
  @entry.command("update")
293
- @click.option('--attribute', required=True, help='Attribute name')
294
- @click.option('--code', help='Entry code to update (only used when --data is provided)')
293
+ @click.option('--id', default=None, help='Entry ID to update (only used with --data for single entry)')
294
+ @click.option('--code', default=None, help='Entry code to update (only used with --data for single entry)')
295
295
  @click.argument('file_path', required=False)
296
296
  @click.option('--data', help='Data string in format { "key1": "value1", "key2": "value2", ... } or a list of such objects')
297
297
  @pass_das_context
298
- def update_entry(das_ctx, attribute, code=None, file_path=None, data=None):
299
- """Update entries from file or data string
298
+ def update_entry(das_ctx, id, code, file_path, data):
299
+ """Update entries from file or data string by ID or code.
300
300
 
301
- Each entry to update must contain a Code field that identifies the entry.
301
+ For single updates, provide either --id or --code (or Id/Code in the data).
302
+ For bulk updates, each entry must contain a Code or Id field.
302
303
  Files can contain multiple entries (rows in CSV/XLS or list of objects in JSON).
303
304
 
304
305
  Examples:
305
306
 
306
307
  \b
307
- # Update entries from JSON file
308
- das entry update --attribute core c:\\data\\entries.json
308
+ # Update by code from data string
309
+ das entry update --code ENT001 --data "{ 'Grant Public Access': 'Yes' }"
309
310
 
310
311
  \b
311
- # Update entries from CSV file
312
- das entry update --attribute core c:\\data\\entries.csv
312
+ # Update by ID from data string
313
+ das entry update --id 9b826efc-36f3-471c-ad18-9c1e00abe4fa --data "{ 'Name': 'Updated' }"
313
314
 
314
315
  \b
315
- # Update entries from Excel file
316
- das entry update --attribute core c:\\data\\entries.xls
316
+ # Update entries from JSON file (each object needs Code or Id)
317
+ das entry update c:\\data\\entries.json
317
318
 
318
319
  \b
319
- # Update a single entry from data string
320
- das entry update --attribute core --code ENT001 --data { 'Grant Public Access': Yes, ... }
320
+ # Update entries from CSV file
321
+ das entry update c:\\data\\entries.csv
321
322
 
322
323
  \b
323
324
  # Update multiple entries from data string
324
- das entry update --attribute core --data [{ 'Code': 'ENT001', ... }, { 'Code': 'ENT002', ... }]
325
+ das entry update --data "[{ 'Code': 'ENT001', ... }, { 'Code': 'ENT002', ... }]"
325
326
  """
326
327
  try:
327
328
  # Ensure client and entry_manager are initialized
@@ -341,13 +342,14 @@ def update_entry(das_ctx, attribute, code=None, file_path=None, data=None):
341
342
  is_bulk_update = True
342
343
  click.echo(f"Found {len(entry_data)} entries to update")
343
344
  else:
344
- # If we got a single object but no code was provided, check if it has a Code field
345
- if not code:
346
- # Look for Code field (case-insensitive)
347
- entry_code = next((entry_data.get(key) for key in entry_data if key.lower() == 'code'), None)
348
- if not entry_code:
349
- raise click.UsageError("No code provided and entry data doesn't contain a Code field")
350
- code = entry_code
345
+ # If we got a single object but no id/code was provided, check if it has Id or Code in data
346
+ if not id and not code:
347
+ data_id = next((entry_data.get(key) for key in entry_data if key.lower() == 'id'), None)
348
+ data_code = next((entry_data.get(key) for key in entry_data if key.lower() == 'code'), None)
349
+ if not data_id and not data_code:
350
+ raise click.UsageError("No --id or --code provided and entry data doesn't contain an Id or Code field")
351
+ id = id or data_id
352
+ code = code or data_code
351
353
 
352
354
  elif data:
353
355
  click.echo("Parsing data string")
@@ -357,19 +359,25 @@ def update_entry(das_ctx, attribute, code=None, file_path=None, data=None):
357
359
  if isinstance(entry_data, list):
358
360
  is_bulk_update = True
359
361
  click.echo(f"Found {len(entry_data)} entries to update")
360
- elif not code:
361
- # If we got a single object but no code was provided, check if it has a Code field
362
- entry_code = next((entry_data.get(key) for key in entry_data if key.lower() == 'code'), None)
363
- if not entry_code:
364
- raise click.UsageError("No code provided and data doesn't contain a Code field")
365
- code = entry_code
362
+ elif not id and not code:
363
+ # If we got a single object but no id/code was provided, check if it has Id or Code in data
364
+ data_id = next((entry_data.get(key) for key in entry_data if key.lower() == 'id'), None)
365
+ data_code = next((entry_data.get(key) for key in entry_data if key.lower() == 'code'), None)
366
+ if not data_id and not data_code:
367
+ raise click.UsageError("No --id or --code provided and data doesn't contain an Id or Code field")
368
+ id = id or data_id
369
+ code = code or data_code
366
370
 
367
371
  if not entry_data:
368
372
  raise click.UsageError("No valid entry data found")
369
373
 
374
+ # For single entry update, require id or code
375
+ if not is_bulk_update and not id and not code:
376
+ raise click.UsageError("Please provide either --id or --code, or include Id or Code in the data")
377
+
370
378
  # Update the entries
371
379
  if is_bulk_update:
372
- results = das_ctx.entry_manager.update(attribute=attribute, entries=entry_data)
380
+ results = das_ctx.entry_manager.update(entries=entry_data)
373
381
 
374
382
  # Display results
375
383
  success_count = sum(1 for result in results if result.get('status') == 'success')
@@ -385,13 +393,16 @@ def update_entry(das_ctx, attribute, code=None, file_path=None, data=None):
385
393
  click.echo("\nFailed updates:")
386
394
  for result in results:
387
395
  if result.get('status') == 'error':
388
- click.echo(f" Code: {result.get('code', 'Unknown')}, Error: {result.get('error', 'Unknown error')}")
396
+ ident = result.get('code') or result.get('id') or 'Unknown'
397
+ click.echo(f" {ident}: {result.get('error', 'Unknown error')}")
389
398
  else:
390
399
  # Single entry update
391
- results = das_ctx.entry_manager.update(attribute=attribute, code=code, entry=entry_data)
400
+ results = das_ctx.entry_manager.update(id=id, code=code, entry=entry_data)
392
401
 
393
402
  if results and results[0].get('status') == 'success':
394
- click.secho(f"✓ Entry '{code}' updated successfully!", fg="green")
403
+ identifier = id or code
404
+ id_label = "ID" if id else "code"
405
+ click.secho(f"✓ Entry '{identifier}' ({id_label}) updated successfully!", fg="green")
395
406
  click.echo(f"Entry ID: {results[0].get('id')}")
396
407
  else:
397
408
  error_msg = results[0].get('error', 'No response from server') if results else 'No response from server'
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}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: das-cli
3
- Version: 1.2.4
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=RiometuuRNK4UZm17f7bfej8xhtS2yYufnKXOJsA4jw,50462
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,11 +9,11 @@ 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
@@ -24,9 +24,9 @@ das/services/entry_fields.py,sha256=x2wUDkKNduj9pf4s56hRo0UW-eBhipkU9gFMEjFw5DA,
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.4.dist-info/licenses/LICENSE,sha256=4EDhysVgQWBlzo0rdUl_k89s-iVfgCcSa1gUx1TM1vA,1124
28
- das_cli-1.2.4.dist-info/METADATA,sha256=SAesRnYIdcNA1LUpbnaLAisw9kzdy-KUNJhH27-xK_4,26209
29
- das_cli-1.2.4.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
30
- das_cli-1.2.4.dist-info/entry_points.txt,sha256=ZrdMae7NcvogQhzM1zun8E8n_QwYq-LpZvoJCr2_I4g,36
31
- das_cli-1.2.4.dist-info/top_level.txt,sha256=OJsPEeJyJ2rJlpEn2DTPgbMSvYG-6FeD13_m5qLpw3E,4
32
- das_cli-1.2.4.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,,