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 +42 -31
- das/common/file_utils.py +3 -0
- das/managers/entries_manager.py +21 -15
- {das_cli-1.2.4.dist-info → das_cli-1.2.6.dist-info}/METADATA +1 -1
- {das_cli-1.2.4.dist-info → das_cli-1.2.6.dist-info}/RECORD +9 -9
- {das_cli-1.2.4.dist-info → das_cli-1.2.6.dist-info}/WHEEL +0 -0
- {das_cli-1.2.4.dist-info → das_cli-1.2.6.dist-info}/entry_points.txt +0 -0
- {das_cli-1.2.4.dist-info → das_cli-1.2.6.dist-info}/licenses/LICENSE +0 -0
- {das_cli-1.2.4.dist-info → das_cli-1.2.6.dist-info}/top_level.txt +0 -0
das/cli.py
CHANGED
|
@@ -290,38 +290,39 @@ def entry():
|
|
|
290
290
|
pass
|
|
291
291
|
|
|
292
292
|
@entry.command("update")
|
|
293
|
-
@click.option('--
|
|
294
|
-
@click.option('--code', help='Entry code to update (only used
|
|
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,
|
|
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
|
-
|
|
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
|
|
308
|
-
das entry update --
|
|
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
|
|
312
|
-
das entry update --
|
|
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
|
|
316
|
-
das entry update
|
|
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
|
|
320
|
-
das entry update
|
|
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 --
|
|
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
|
|
345
|
-
if not code:
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
if not
|
|
349
|
-
raise click.UsageError("No code provided and entry data doesn't contain
|
|
350
|
-
|
|
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
|
|
362
|
-
|
|
363
|
-
if
|
|
364
|
-
|
|
365
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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:
|
das/managers/entries_manager.py
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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,
|
|
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
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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
|
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=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
|
|
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=
|
|
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.
|
|
28
|
-
das_cli-1.2.
|
|
29
|
-
das_cli-1.2.
|
|
30
|
-
das_cli-1.2.
|
|
31
|
-
das_cli-1.2.
|
|
32
|
-
das_cli-1.2.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|