pltr-cli 0.6.0__py3-none-any.whl → 0.8.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.
- pltr/__init__.py +1 -1
- pltr/commands/dataset.py +764 -2
- pltr/services/dataset.py +624 -3
- pltr/utils/formatting.py +170 -0
- {pltr_cli-0.6.0.dist-info → pltr_cli-0.8.0.dist-info}/METADATA +1 -1
- {pltr_cli-0.6.0.dist-info → pltr_cli-0.8.0.dist-info}/RECORD +9 -9
- {pltr_cli-0.6.0.dist-info → pltr_cli-0.8.0.dist-info}/WHEEL +0 -0
- {pltr_cli-0.6.0.dist-info → pltr_cli-0.8.0.dist-info}/entry_points.txt +0 -0
- {pltr_cli-0.6.0.dist-info → pltr_cli-0.8.0.dist-info}/licenses/LICENSE +0 -0
pltr/commands/dataset.py
CHANGED
|
@@ -22,6 +22,9 @@ branches_app = typer.Typer()
|
|
|
22
22
|
files_app = typer.Typer()
|
|
23
23
|
transactions_app = typer.Typer()
|
|
24
24
|
views_app = typer.Typer()
|
|
25
|
+
schema_app = typer.Typer()
|
|
26
|
+
schedules_app = typer.Typer()
|
|
27
|
+
jobs_app = typer.Typer()
|
|
25
28
|
console = Console()
|
|
26
29
|
formatter = OutputFormatter(console)
|
|
27
30
|
|
|
@@ -70,7 +73,175 @@ def get_dataset(
|
|
|
70
73
|
raise typer.Exit(1)
|
|
71
74
|
|
|
72
75
|
|
|
73
|
-
#
|
|
76
|
+
# Schema commands
|
|
77
|
+
@schema_app.command("get")
|
|
78
|
+
def get_schema(
|
|
79
|
+
dataset_rid: str = typer.Argument(
|
|
80
|
+
..., help="Dataset Resource Identifier", autocompletion=complete_rid
|
|
81
|
+
),
|
|
82
|
+
profile: Optional[str] = typer.Option(
|
|
83
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
84
|
+
),
|
|
85
|
+
format: str = typer.Option(
|
|
86
|
+
"table",
|
|
87
|
+
"--format",
|
|
88
|
+
"-f",
|
|
89
|
+
help="Output format (table, json, csv)",
|
|
90
|
+
autocompletion=complete_output_format,
|
|
91
|
+
),
|
|
92
|
+
output: Optional[str] = typer.Option(
|
|
93
|
+
None, "--output", "-o", help="Output file path"
|
|
94
|
+
),
|
|
95
|
+
):
|
|
96
|
+
"""Get the schema of a dataset."""
|
|
97
|
+
try:
|
|
98
|
+
cache_rid(dataset_rid)
|
|
99
|
+
service = DatasetService(profile=profile)
|
|
100
|
+
|
|
101
|
+
with SpinnerProgressTracker().track_spinner(
|
|
102
|
+
f"Fetching schema for {dataset_rid}..."
|
|
103
|
+
):
|
|
104
|
+
schema = service.get_schema(dataset_rid)
|
|
105
|
+
|
|
106
|
+
# Format schema for display
|
|
107
|
+
if format == "json":
|
|
108
|
+
formatter._format_json(schema, output)
|
|
109
|
+
else:
|
|
110
|
+
formatter.print_info(f"Dataset: {dataset_rid}")
|
|
111
|
+
formatter.print_info(f"Status: {schema.get('status', 'Unknown')}")
|
|
112
|
+
if schema.get("schema"):
|
|
113
|
+
formatter.print_info("\nSchema:")
|
|
114
|
+
formatter._format_json(schema.get("schema"))
|
|
115
|
+
|
|
116
|
+
if output:
|
|
117
|
+
formatter.print_success(f"Schema saved to {output}")
|
|
118
|
+
|
|
119
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
120
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
121
|
+
raise typer.Exit(1)
|
|
122
|
+
except Exception as e:
|
|
123
|
+
formatter.print_error(f"Failed to get schema: {e}")
|
|
124
|
+
raise typer.Exit(1)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@schema_app.command("set")
|
|
128
|
+
def set_schema(
|
|
129
|
+
dataset_rid: str = typer.Argument(
|
|
130
|
+
..., help="Dataset Resource Identifier", autocompletion=complete_rid
|
|
131
|
+
),
|
|
132
|
+
from_csv: Optional[str] = typer.Option(
|
|
133
|
+
None, "--from-csv", help="Infer schema from CSV file"
|
|
134
|
+
),
|
|
135
|
+
json_schema: Optional[str] = typer.Option(
|
|
136
|
+
None, "--json", help="JSON string defining the schema"
|
|
137
|
+
),
|
|
138
|
+
json_file: Optional[str] = typer.Option(
|
|
139
|
+
None, "--json-file", help="Path to JSON file containing schema definition"
|
|
140
|
+
),
|
|
141
|
+
branch: str = typer.Option("master", "--branch", help="Dataset branch"),
|
|
142
|
+
transaction_rid: Optional[str] = typer.Option(
|
|
143
|
+
None, "--transaction-rid", help="Transaction RID to use"
|
|
144
|
+
),
|
|
145
|
+
profile: Optional[str] = typer.Option(
|
|
146
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
147
|
+
),
|
|
148
|
+
):
|
|
149
|
+
"""Set or update the schema of a dataset."""
|
|
150
|
+
try:
|
|
151
|
+
cache_rid(dataset_rid)
|
|
152
|
+
service = DatasetService(profile=profile)
|
|
153
|
+
|
|
154
|
+
# Validate that exactly one input method is provided
|
|
155
|
+
input_methods = [from_csv, json_schema, json_file]
|
|
156
|
+
if sum(x is not None for x in input_methods) != 1:
|
|
157
|
+
formatter.print_error(
|
|
158
|
+
"Exactly one of --from-csv, --json, or --json-file must be provided"
|
|
159
|
+
)
|
|
160
|
+
raise typer.Exit(1)
|
|
161
|
+
|
|
162
|
+
schema = None
|
|
163
|
+
|
|
164
|
+
# Infer schema from CSV
|
|
165
|
+
if from_csv:
|
|
166
|
+
with SpinnerProgressTracker().track_spinner(
|
|
167
|
+
f"Inferring schema from {from_csv}..."
|
|
168
|
+
):
|
|
169
|
+
schema = service.infer_schema_from_csv(from_csv)
|
|
170
|
+
formatter.print_info(
|
|
171
|
+
f"Inferred schema from CSV with {len(schema.field_schema_list)} fields"
|
|
172
|
+
)
|
|
173
|
+
for field in schema.field_schema_list:
|
|
174
|
+
formatter.print_info(
|
|
175
|
+
f" - {field.name}: {field.type} (nullable={field.nullable})"
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
# Parse schema from JSON string
|
|
179
|
+
elif json_schema:
|
|
180
|
+
import json
|
|
181
|
+
from foundry_sdk.v2.core.models import DatasetSchema, DatasetFieldSchema
|
|
182
|
+
|
|
183
|
+
try:
|
|
184
|
+
schema_data = json.loads(json_schema)
|
|
185
|
+
fields = []
|
|
186
|
+
for field_data in schema_data.get("fields", []):
|
|
187
|
+
fields.append(
|
|
188
|
+
DatasetFieldSchema(
|
|
189
|
+
name=field_data["name"],
|
|
190
|
+
type=field_data["type"],
|
|
191
|
+
nullable=field_data.get("nullable", True),
|
|
192
|
+
)
|
|
193
|
+
)
|
|
194
|
+
schema = DatasetSchema(field_schema_list=fields)
|
|
195
|
+
except (json.JSONDecodeError, KeyError) as e:
|
|
196
|
+
formatter.print_error(f"Invalid JSON schema: {e}")
|
|
197
|
+
raise typer.Exit(1)
|
|
198
|
+
|
|
199
|
+
# Load schema from JSON file
|
|
200
|
+
elif json_file:
|
|
201
|
+
import json
|
|
202
|
+
from foundry_sdk.v2.core.models import DatasetSchema, DatasetFieldSchema
|
|
203
|
+
|
|
204
|
+
try:
|
|
205
|
+
with open(json_file, "r") as f:
|
|
206
|
+
schema_data = json.load(f)
|
|
207
|
+
fields = []
|
|
208
|
+
for field_data in schema_data.get("fields", []):
|
|
209
|
+
fields.append(
|
|
210
|
+
DatasetFieldSchema(
|
|
211
|
+
name=field_data["name"],
|
|
212
|
+
type=field_data["type"],
|
|
213
|
+
nullable=field_data.get("nullable", True),
|
|
214
|
+
)
|
|
215
|
+
)
|
|
216
|
+
schema = DatasetSchema(field_schema_list=fields)
|
|
217
|
+
except (FileNotFoundError, json.JSONDecodeError, KeyError) as e:
|
|
218
|
+
formatter.print_error(f"Failed to load schema from file: {e}")
|
|
219
|
+
raise typer.Exit(1)
|
|
220
|
+
|
|
221
|
+
# Apply the schema
|
|
222
|
+
with SpinnerProgressTracker().track_spinner(
|
|
223
|
+
f"Setting schema on dataset {dataset_rid}..."
|
|
224
|
+
):
|
|
225
|
+
service.put_schema(
|
|
226
|
+
dataset_rid=dataset_rid,
|
|
227
|
+
schema=schema,
|
|
228
|
+
branch=branch,
|
|
229
|
+
transaction_rid=transaction_rid,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
formatter.print_success(f"Successfully set schema on dataset {dataset_rid}")
|
|
233
|
+
if transaction_rid:
|
|
234
|
+
formatter.print_info(f"Transaction RID: {transaction_rid}")
|
|
235
|
+
|
|
236
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
237
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
238
|
+
raise typer.Exit(1)
|
|
239
|
+
except FileNotFoundError as e:
|
|
240
|
+
formatter.print_error(f"File not found: {e}")
|
|
241
|
+
raise typer.Exit(1)
|
|
242
|
+
except Exception as e:
|
|
243
|
+
formatter.print_error(f"Failed to set schema: {e}")
|
|
244
|
+
raise typer.Exit(1)
|
|
74
245
|
|
|
75
246
|
|
|
76
247
|
@app.command("create")
|
|
@@ -189,6 +360,139 @@ def create_branch(
|
|
|
189
360
|
raise typer.Exit(1)
|
|
190
361
|
|
|
191
362
|
|
|
363
|
+
@branches_app.command("delete")
|
|
364
|
+
def delete_branch(
|
|
365
|
+
dataset_rid: str = typer.Argument(
|
|
366
|
+
..., help="Dataset Resource Identifier", autocompletion=complete_rid
|
|
367
|
+
),
|
|
368
|
+
branch_name: str = typer.Argument(..., help="Branch name to delete"),
|
|
369
|
+
confirm: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation prompt"),
|
|
370
|
+
profile: Optional[str] = typer.Option(
|
|
371
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
372
|
+
),
|
|
373
|
+
):
|
|
374
|
+
"""Delete a branch from a dataset."""
|
|
375
|
+
try:
|
|
376
|
+
cache_rid(dataset_rid)
|
|
377
|
+
service = DatasetService(profile=profile)
|
|
378
|
+
|
|
379
|
+
# Prevent deleting master branch
|
|
380
|
+
if branch_name.lower() == "master":
|
|
381
|
+
formatter.print_error("Cannot delete the master branch")
|
|
382
|
+
raise typer.Exit(1)
|
|
383
|
+
|
|
384
|
+
# Confirmation prompt
|
|
385
|
+
if not confirm:
|
|
386
|
+
confirmed = typer.confirm(
|
|
387
|
+
f"Are you sure you want to delete branch '{branch_name}' from dataset {dataset_rid}? "
|
|
388
|
+
f"This action cannot be undone."
|
|
389
|
+
)
|
|
390
|
+
if not confirmed:
|
|
391
|
+
formatter.print_info("Branch deletion cancelled")
|
|
392
|
+
raise typer.Exit(0)
|
|
393
|
+
|
|
394
|
+
with SpinnerProgressTracker().track_spinner(
|
|
395
|
+
f"Deleting branch '{branch_name}' from {dataset_rid}..."
|
|
396
|
+
):
|
|
397
|
+
service.delete_branch(dataset_rid, branch_name)
|
|
398
|
+
|
|
399
|
+
formatter.print_success(f"Branch '{branch_name}' deleted successfully")
|
|
400
|
+
formatter.print_info(f"Dataset: {dataset_rid}")
|
|
401
|
+
|
|
402
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
403
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
404
|
+
raise typer.Exit(1)
|
|
405
|
+
except Exception as e:
|
|
406
|
+
formatter.print_error(f"Failed to delete branch: {e}")
|
|
407
|
+
raise typer.Exit(1)
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
@branches_app.command("get")
|
|
411
|
+
def get_branch(
|
|
412
|
+
dataset_rid: str = typer.Argument(
|
|
413
|
+
..., help="Dataset Resource Identifier", autocompletion=complete_rid
|
|
414
|
+
),
|
|
415
|
+
branch_name: str = typer.Argument(..., help="Branch name"),
|
|
416
|
+
profile: Optional[str] = typer.Option(
|
|
417
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
418
|
+
),
|
|
419
|
+
format: str = typer.Option(
|
|
420
|
+
"table",
|
|
421
|
+
"--format",
|
|
422
|
+
"-f",
|
|
423
|
+
help="Output format (table, json, csv)",
|
|
424
|
+
autocompletion=complete_output_format,
|
|
425
|
+
),
|
|
426
|
+
output: Optional[str] = typer.Option(
|
|
427
|
+
None, "--output", "-o", help="Output file path"
|
|
428
|
+
),
|
|
429
|
+
):
|
|
430
|
+
"""Get detailed information about a specific branch."""
|
|
431
|
+
try:
|
|
432
|
+
cache_rid(dataset_rid)
|
|
433
|
+
service = DatasetService(profile=profile)
|
|
434
|
+
|
|
435
|
+
with SpinnerProgressTracker().track_spinner(
|
|
436
|
+
f"Fetching branch '{branch_name}' from {dataset_rid}..."
|
|
437
|
+
):
|
|
438
|
+
branch = service.get_branch(dataset_rid, branch_name)
|
|
439
|
+
|
|
440
|
+
formatter.format_branch_detail(branch, format, output)
|
|
441
|
+
|
|
442
|
+
if output:
|
|
443
|
+
formatter.print_success(f"Branch information saved to {output}")
|
|
444
|
+
|
|
445
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
446
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
447
|
+
raise typer.Exit(1)
|
|
448
|
+
except Exception as e:
|
|
449
|
+
formatter.print_error(f"Failed to get branch: {e}")
|
|
450
|
+
raise typer.Exit(1)
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
@branches_app.command("transactions")
|
|
454
|
+
def list_branch_transactions(
|
|
455
|
+
dataset_rid: str = typer.Argument(
|
|
456
|
+
..., help="Dataset Resource Identifier", autocompletion=complete_rid
|
|
457
|
+
),
|
|
458
|
+
branch_name: str = typer.Argument(..., help="Branch name"),
|
|
459
|
+
profile: Optional[str] = typer.Option(
|
|
460
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
461
|
+
),
|
|
462
|
+
format: str = typer.Option(
|
|
463
|
+
"table",
|
|
464
|
+
"--format",
|
|
465
|
+
"-f",
|
|
466
|
+
help="Output format (table, json, csv)",
|
|
467
|
+
autocompletion=complete_output_format,
|
|
468
|
+
),
|
|
469
|
+
output: Optional[str] = typer.Option(
|
|
470
|
+
None, "--output", "-o", help="Output file path"
|
|
471
|
+
),
|
|
472
|
+
):
|
|
473
|
+
"""Get transaction history for a specific branch."""
|
|
474
|
+
try:
|
|
475
|
+
cache_rid(dataset_rid)
|
|
476
|
+
service = DatasetService(profile=profile)
|
|
477
|
+
|
|
478
|
+
with SpinnerProgressTracker().track_spinner(
|
|
479
|
+
f"Fetching transaction history for branch '{branch_name}' in {dataset_rid}..."
|
|
480
|
+
):
|
|
481
|
+
transactions = service.get_branch_transactions(dataset_rid, branch_name)
|
|
482
|
+
|
|
483
|
+
formatter.format_transactions(transactions, format, output)
|
|
484
|
+
|
|
485
|
+
if output:
|
|
486
|
+
formatter.print_success(f"Branch transactions saved to {output}")
|
|
487
|
+
|
|
488
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
489
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
490
|
+
raise typer.Exit(1)
|
|
491
|
+
except Exception as e:
|
|
492
|
+
formatter.print_error(f"Failed to get branch transactions: {e}")
|
|
493
|
+
raise typer.Exit(1)
|
|
494
|
+
|
|
495
|
+
|
|
192
496
|
# Files commands
|
|
193
497
|
@files_app.command("list")
|
|
194
498
|
def list_files(
|
|
@@ -281,9 +585,30 @@ def upload_file(
|
|
|
281
585
|
|
|
282
586
|
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
283
587
|
formatter.print_error(f"Authentication error: {e}")
|
|
588
|
+
raise typer.Exit(1)
|
|
589
|
+
except FileNotFoundError as e:
|
|
590
|
+
formatter.print_error(f"File error: {e}")
|
|
591
|
+
raise typer.Exit(1)
|
|
592
|
+
except RuntimeError as e:
|
|
593
|
+
# RuntimeError from our service layer contains detailed error info
|
|
594
|
+
error_msg = str(e)
|
|
595
|
+
formatter.print_error(f"Upload failed: {error_msg}")
|
|
596
|
+
|
|
597
|
+
# If it looks like our enhanced error message, extract the suggestion part
|
|
598
|
+
if ". Suggestions: " in error_msg:
|
|
599
|
+
main_error, suggestions = error_msg.split(". Suggestions: ", 1)
|
|
600
|
+
formatter.print_error(main_error)
|
|
601
|
+
formatter.print_info(f"💡 Suggestions: {suggestions}")
|
|
602
|
+
|
|
284
603
|
raise typer.Exit(1)
|
|
285
604
|
except Exception as e:
|
|
286
|
-
|
|
605
|
+
# Fallback for any other exceptions
|
|
606
|
+
formatter.print_error(
|
|
607
|
+
f"Unexpected error during file upload: {type(e).__name__}: {e}"
|
|
608
|
+
)
|
|
609
|
+
formatter.print_info(
|
|
610
|
+
"💡 Try running the command again or check your connection"
|
|
611
|
+
)
|
|
287
612
|
raise typer.Exit(1)
|
|
288
613
|
|
|
289
614
|
|
|
@@ -320,6 +645,93 @@ def get_file(
|
|
|
320
645
|
raise typer.Exit(1)
|
|
321
646
|
|
|
322
647
|
|
|
648
|
+
@files_app.command("delete")
|
|
649
|
+
def delete_file(
|
|
650
|
+
dataset_rid: str = typer.Argument(
|
|
651
|
+
..., help="Dataset Resource Identifier", autocompletion=complete_rid
|
|
652
|
+
),
|
|
653
|
+
file_path: str = typer.Argument(..., help="Path of file within dataset to delete"),
|
|
654
|
+
branch: str = typer.Option("master", "--branch", help="Dataset branch"),
|
|
655
|
+
confirm: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation prompt"),
|
|
656
|
+
profile: Optional[str] = typer.Option(
|
|
657
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
658
|
+
),
|
|
659
|
+
):
|
|
660
|
+
"""Delete a file from a dataset."""
|
|
661
|
+
try:
|
|
662
|
+
cache_rid(dataset_rid)
|
|
663
|
+
service = DatasetService(profile=profile)
|
|
664
|
+
|
|
665
|
+
# Confirmation prompt
|
|
666
|
+
if not confirm:
|
|
667
|
+
confirmed = typer.confirm(
|
|
668
|
+
f"Are you sure you want to delete '{file_path}' from dataset {dataset_rid}?"
|
|
669
|
+
)
|
|
670
|
+
if not confirmed:
|
|
671
|
+
formatter.print_info("File deletion cancelled")
|
|
672
|
+
raise typer.Exit(0)
|
|
673
|
+
|
|
674
|
+
with SpinnerProgressTracker().track_spinner(
|
|
675
|
+
f"Deleting {file_path} from {dataset_rid}..."
|
|
676
|
+
):
|
|
677
|
+
service.delete_file(dataset_rid, file_path, branch)
|
|
678
|
+
|
|
679
|
+
formatter.print_success(f"File '{file_path}' deleted successfully")
|
|
680
|
+
formatter.print_info(f"Dataset: {dataset_rid}")
|
|
681
|
+
formatter.print_info(f"Branch: {branch}")
|
|
682
|
+
|
|
683
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
684
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
685
|
+
raise typer.Exit(1)
|
|
686
|
+
except Exception as e:
|
|
687
|
+
formatter.print_error(f"Failed to delete file: {e}")
|
|
688
|
+
raise typer.Exit(1)
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
@files_app.command("info")
|
|
692
|
+
def get_file_info(
|
|
693
|
+
dataset_rid: str = typer.Argument(
|
|
694
|
+
..., help="Dataset Resource Identifier", autocompletion=complete_rid
|
|
695
|
+
),
|
|
696
|
+
file_path: str = typer.Argument(..., help="Path of file within dataset"),
|
|
697
|
+
branch: str = typer.Option("master", "--branch", help="Dataset branch"),
|
|
698
|
+
profile: Optional[str] = typer.Option(
|
|
699
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
700
|
+
),
|
|
701
|
+
format: str = typer.Option(
|
|
702
|
+
"table",
|
|
703
|
+
"--format",
|
|
704
|
+
"-f",
|
|
705
|
+
help="Output format (table, json, csv)",
|
|
706
|
+
autocompletion=complete_output_format,
|
|
707
|
+
),
|
|
708
|
+
output: Optional[str] = typer.Option(
|
|
709
|
+
None, "--output", "-o", help="Output file path"
|
|
710
|
+
),
|
|
711
|
+
):
|
|
712
|
+
"""Get metadata information about a file in a dataset."""
|
|
713
|
+
try:
|
|
714
|
+
cache_rid(dataset_rid)
|
|
715
|
+
service = DatasetService(profile=profile)
|
|
716
|
+
|
|
717
|
+
with SpinnerProgressTracker().track_spinner(
|
|
718
|
+
f"Getting file info for {file_path} in {dataset_rid}..."
|
|
719
|
+
):
|
|
720
|
+
file_info = service.get_file_info(dataset_rid, file_path, branch)
|
|
721
|
+
|
|
722
|
+
formatter.format_file_info(file_info, format, output)
|
|
723
|
+
|
|
724
|
+
if output:
|
|
725
|
+
formatter.print_success(f"File information saved to {output}")
|
|
726
|
+
|
|
727
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
728
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
729
|
+
raise typer.Exit(1)
|
|
730
|
+
except Exception as e:
|
|
731
|
+
formatter.print_error(f"Failed to get file info: {e}")
|
|
732
|
+
raise typer.Exit(1)
|
|
733
|
+
|
|
734
|
+
|
|
323
735
|
# Transaction commands
|
|
324
736
|
@transactions_app.command("start")
|
|
325
737
|
def start_transaction(
|
|
@@ -581,6 +993,49 @@ def list_transactions(
|
|
|
581
993
|
raise typer.Exit(1)
|
|
582
994
|
|
|
583
995
|
|
|
996
|
+
@transactions_app.command("build")
|
|
997
|
+
def get_transaction_build(
|
|
998
|
+
dataset_rid: str = typer.Argument(
|
|
999
|
+
..., help="Dataset Resource Identifier", autocompletion=complete_rid
|
|
1000
|
+
),
|
|
1001
|
+
transaction_rid: str = typer.Argument(..., help="Transaction Resource Identifier"),
|
|
1002
|
+
profile: Optional[str] = typer.Option(
|
|
1003
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
1004
|
+
),
|
|
1005
|
+
format: str = typer.Option(
|
|
1006
|
+
"table",
|
|
1007
|
+
"--format",
|
|
1008
|
+
"-f",
|
|
1009
|
+
help="Output format (table, json, csv)",
|
|
1010
|
+
autocompletion=complete_output_format,
|
|
1011
|
+
),
|
|
1012
|
+
output: Optional[str] = typer.Option(
|
|
1013
|
+
None, "--output", "-o", help="Output file path"
|
|
1014
|
+
),
|
|
1015
|
+
):
|
|
1016
|
+
"""Get build information for a transaction."""
|
|
1017
|
+
try:
|
|
1018
|
+
cache_rid(dataset_rid)
|
|
1019
|
+
service = DatasetService(profile=profile)
|
|
1020
|
+
|
|
1021
|
+
with SpinnerProgressTracker().track_spinner(
|
|
1022
|
+
f"Fetching build information for transaction {transaction_rid}..."
|
|
1023
|
+
):
|
|
1024
|
+
build_info = service.get_transaction_build(dataset_rid, transaction_rid)
|
|
1025
|
+
|
|
1026
|
+
formatter.format_transaction_build(build_info, format, output)
|
|
1027
|
+
|
|
1028
|
+
if output:
|
|
1029
|
+
formatter.print_success(f"Build information saved to {output}")
|
|
1030
|
+
|
|
1031
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
1032
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
1033
|
+
raise typer.Exit(1)
|
|
1034
|
+
except Exception as e:
|
|
1035
|
+
formatter.print_error(f"Failed to get transaction build: {e}")
|
|
1036
|
+
raise typer.Exit(1)
|
|
1037
|
+
|
|
1038
|
+
|
|
584
1039
|
# Views commands
|
|
585
1040
|
@views_app.command("list")
|
|
586
1041
|
def list_views(
|
|
@@ -627,6 +1082,223 @@ def list_views(
|
|
|
627
1082
|
raise typer.Exit(1)
|
|
628
1083
|
|
|
629
1084
|
|
|
1085
|
+
@views_app.command("get")
|
|
1086
|
+
def get_view(
|
|
1087
|
+
view_rid: str = typer.Argument(
|
|
1088
|
+
..., help="View Resource Identifier", autocompletion=complete_rid
|
|
1089
|
+
),
|
|
1090
|
+
branch: str = typer.Option("master", "--branch", help="Branch name"),
|
|
1091
|
+
profile: Optional[str] = typer.Option(
|
|
1092
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
1093
|
+
),
|
|
1094
|
+
format: str = typer.Option(
|
|
1095
|
+
"table",
|
|
1096
|
+
"--format",
|
|
1097
|
+
"-f",
|
|
1098
|
+
help="Output format (table, json, csv)",
|
|
1099
|
+
autocompletion=complete_output_format,
|
|
1100
|
+
),
|
|
1101
|
+
output: Optional[str] = typer.Option(
|
|
1102
|
+
None, "--output", "-o", help="Output file path"
|
|
1103
|
+
),
|
|
1104
|
+
):
|
|
1105
|
+
"""Get detailed information about a view."""
|
|
1106
|
+
try:
|
|
1107
|
+
cache_rid(view_rid)
|
|
1108
|
+
service = DatasetService(profile=profile)
|
|
1109
|
+
|
|
1110
|
+
with SpinnerProgressTracker().track_spinner(f"Fetching view {view_rid}..."):
|
|
1111
|
+
view = service.get_view(view_rid, branch)
|
|
1112
|
+
|
|
1113
|
+
formatter.format_view_detail(view, format, output)
|
|
1114
|
+
|
|
1115
|
+
if output:
|
|
1116
|
+
formatter.print_success(f"View information saved to {output}")
|
|
1117
|
+
|
|
1118
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
1119
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
1120
|
+
raise typer.Exit(1)
|
|
1121
|
+
except Exception as e:
|
|
1122
|
+
formatter.print_error(f"Failed to get view: {e}")
|
|
1123
|
+
raise typer.Exit(1)
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
@views_app.command("add-datasets")
|
|
1127
|
+
def add_backing_datasets(
|
|
1128
|
+
view_rid: str = typer.Argument(
|
|
1129
|
+
..., help="View Resource Identifier", autocompletion=complete_rid
|
|
1130
|
+
),
|
|
1131
|
+
dataset_rids: list[str] = typer.Argument(
|
|
1132
|
+
..., help="Dataset RIDs to add as backing datasets"
|
|
1133
|
+
),
|
|
1134
|
+
profile: Optional[str] = typer.Option(
|
|
1135
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
1136
|
+
),
|
|
1137
|
+
format: str = typer.Option(
|
|
1138
|
+
"table",
|
|
1139
|
+
"--format",
|
|
1140
|
+
"-f",
|
|
1141
|
+
help="Output format (table, json, csv)",
|
|
1142
|
+
autocompletion=complete_output_format,
|
|
1143
|
+
),
|
|
1144
|
+
):
|
|
1145
|
+
"""Add backing datasets to a view."""
|
|
1146
|
+
try:
|
|
1147
|
+
cache_rid(view_rid)
|
|
1148
|
+
service = DatasetService(profile=profile)
|
|
1149
|
+
|
|
1150
|
+
with SpinnerProgressTracker().track_spinner(
|
|
1151
|
+
f"Adding {len(dataset_rids)} backing datasets to view {view_rid}..."
|
|
1152
|
+
):
|
|
1153
|
+
result = service.add_backing_datasets(view_rid, dataset_rids)
|
|
1154
|
+
|
|
1155
|
+
formatter.print_success("Successfully added backing datasets to view")
|
|
1156
|
+
formatter.print_info(f"View RID: {view_rid}")
|
|
1157
|
+
formatter.print_info(f"Added datasets: {', '.join(dataset_rids)}")
|
|
1158
|
+
|
|
1159
|
+
if format == "json":
|
|
1160
|
+
formatter._format_json(result)
|
|
1161
|
+
|
|
1162
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
1163
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
1164
|
+
raise typer.Exit(1)
|
|
1165
|
+
except Exception as e:
|
|
1166
|
+
formatter.print_error(f"Failed to add backing datasets: {e}")
|
|
1167
|
+
raise typer.Exit(1)
|
|
1168
|
+
|
|
1169
|
+
|
|
1170
|
+
@views_app.command("remove-datasets")
|
|
1171
|
+
def remove_backing_datasets(
|
|
1172
|
+
view_rid: str = typer.Argument(
|
|
1173
|
+
..., help="View Resource Identifier", autocompletion=complete_rid
|
|
1174
|
+
),
|
|
1175
|
+
dataset_rids: list[str] = typer.Argument(
|
|
1176
|
+
..., help="Dataset RIDs to remove as backing datasets"
|
|
1177
|
+
),
|
|
1178
|
+
profile: Optional[str] = typer.Option(
|
|
1179
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
1180
|
+
),
|
|
1181
|
+
format: str = typer.Option(
|
|
1182
|
+
"table",
|
|
1183
|
+
"--format",
|
|
1184
|
+
"-f",
|
|
1185
|
+
help="Output format (table, json, csv)",
|
|
1186
|
+
autocompletion=complete_output_format,
|
|
1187
|
+
),
|
|
1188
|
+
):
|
|
1189
|
+
"""Remove backing datasets from a view."""
|
|
1190
|
+
try:
|
|
1191
|
+
cache_rid(view_rid)
|
|
1192
|
+
service = DatasetService(profile=profile)
|
|
1193
|
+
|
|
1194
|
+
with SpinnerProgressTracker().track_spinner(
|
|
1195
|
+
f"Removing {len(dataset_rids)} backing datasets from view {view_rid}..."
|
|
1196
|
+
):
|
|
1197
|
+
result = service.remove_backing_datasets(view_rid, dataset_rids)
|
|
1198
|
+
|
|
1199
|
+
formatter.print_success("Successfully removed backing datasets from view")
|
|
1200
|
+
formatter.print_info(f"View RID: {view_rid}")
|
|
1201
|
+
formatter.print_info(f"Removed datasets: {', '.join(dataset_rids)}")
|
|
1202
|
+
|
|
1203
|
+
if format == "json":
|
|
1204
|
+
formatter._format_json(result)
|
|
1205
|
+
|
|
1206
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
1207
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
1208
|
+
raise typer.Exit(1)
|
|
1209
|
+
except Exception as e:
|
|
1210
|
+
formatter.print_error(f"Failed to remove backing datasets: {e}")
|
|
1211
|
+
raise typer.Exit(1)
|
|
1212
|
+
|
|
1213
|
+
|
|
1214
|
+
@views_app.command("replace-datasets")
|
|
1215
|
+
def replace_backing_datasets(
|
|
1216
|
+
view_rid: str = typer.Argument(
|
|
1217
|
+
..., help="View Resource Identifier", autocompletion=complete_rid
|
|
1218
|
+
),
|
|
1219
|
+
dataset_rids: list[str] = typer.Argument(
|
|
1220
|
+
..., help="Dataset RIDs to set as backing datasets"
|
|
1221
|
+
),
|
|
1222
|
+
profile: Optional[str] = typer.Option(
|
|
1223
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
1224
|
+
),
|
|
1225
|
+
format: str = typer.Option(
|
|
1226
|
+
"table",
|
|
1227
|
+
"--format",
|
|
1228
|
+
"-f",
|
|
1229
|
+
help="Output format (table, json, csv)",
|
|
1230
|
+
autocompletion=complete_output_format,
|
|
1231
|
+
),
|
|
1232
|
+
):
|
|
1233
|
+
"""Replace all backing datasets in a view."""
|
|
1234
|
+
try:
|
|
1235
|
+
cache_rid(view_rid)
|
|
1236
|
+
service = DatasetService(profile=profile)
|
|
1237
|
+
|
|
1238
|
+
with SpinnerProgressTracker().track_spinner(
|
|
1239
|
+
f"Replacing backing datasets in view {view_rid} with {len(dataset_rids)} new datasets..."
|
|
1240
|
+
):
|
|
1241
|
+
result = service.replace_backing_datasets(view_rid, dataset_rids)
|
|
1242
|
+
|
|
1243
|
+
formatter.print_success("Successfully replaced backing datasets in view")
|
|
1244
|
+
formatter.print_info(f"View RID: {view_rid}")
|
|
1245
|
+
formatter.print_info(f"New datasets: {', '.join(dataset_rids)}")
|
|
1246
|
+
|
|
1247
|
+
if format == "json":
|
|
1248
|
+
formatter._format_json(result)
|
|
1249
|
+
|
|
1250
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
1251
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
1252
|
+
raise typer.Exit(1)
|
|
1253
|
+
except Exception as e:
|
|
1254
|
+
formatter.print_error(f"Failed to replace backing datasets: {e}")
|
|
1255
|
+
raise typer.Exit(1)
|
|
1256
|
+
|
|
1257
|
+
|
|
1258
|
+
@views_app.command("add-primary-key")
|
|
1259
|
+
def add_primary_key(
|
|
1260
|
+
view_rid: str = typer.Argument(
|
|
1261
|
+
..., help="View Resource Identifier", autocompletion=complete_rid
|
|
1262
|
+
),
|
|
1263
|
+
key_fields: list[str] = typer.Argument(
|
|
1264
|
+
..., help="Field names to use as primary key"
|
|
1265
|
+
),
|
|
1266
|
+
profile: Optional[str] = typer.Option(
|
|
1267
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
1268
|
+
),
|
|
1269
|
+
format: str = typer.Option(
|
|
1270
|
+
"table",
|
|
1271
|
+
"--format",
|
|
1272
|
+
"-f",
|
|
1273
|
+
help="Output format (table, json, csv)",
|
|
1274
|
+
autocompletion=complete_output_format,
|
|
1275
|
+
),
|
|
1276
|
+
):
|
|
1277
|
+
"""Add a primary key to a view."""
|
|
1278
|
+
try:
|
|
1279
|
+
cache_rid(view_rid)
|
|
1280
|
+
service = DatasetService(profile=profile)
|
|
1281
|
+
|
|
1282
|
+
with SpinnerProgressTracker().track_spinner(
|
|
1283
|
+
f"Adding primary key to view {view_rid}..."
|
|
1284
|
+
):
|
|
1285
|
+
result = service.add_primary_key(view_rid, key_fields)
|
|
1286
|
+
|
|
1287
|
+
formatter.print_success("Successfully added primary key to view")
|
|
1288
|
+
formatter.print_info(f"View RID: {view_rid}")
|
|
1289
|
+
formatter.print_info(f"Primary key fields: {', '.join(key_fields)}")
|
|
1290
|
+
|
|
1291
|
+
if format == "json":
|
|
1292
|
+
formatter._format_json(result)
|
|
1293
|
+
|
|
1294
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
1295
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
1296
|
+
raise typer.Exit(1)
|
|
1297
|
+
except Exception as e:
|
|
1298
|
+
formatter.print_error(f"Failed to add primary key: {e}")
|
|
1299
|
+
raise typer.Exit(1)
|
|
1300
|
+
|
|
1301
|
+
|
|
630
1302
|
@views_app.command("create")
|
|
631
1303
|
def create_view(
|
|
632
1304
|
dataset_rid: str = typer.Argument(
|
|
@@ -671,11 +1343,101 @@ def create_view(
|
|
|
671
1343
|
raise typer.Exit(1)
|
|
672
1344
|
|
|
673
1345
|
|
|
1346
|
+
# Schedules commands
|
|
1347
|
+
@schedules_app.command("list")
|
|
1348
|
+
def list_schedules(
|
|
1349
|
+
dataset_rid: str = typer.Argument(
|
|
1350
|
+
..., help="Dataset Resource Identifier", autocompletion=complete_rid
|
|
1351
|
+
),
|
|
1352
|
+
profile: Optional[str] = typer.Option(
|
|
1353
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
1354
|
+
),
|
|
1355
|
+
format: str = typer.Option(
|
|
1356
|
+
"table",
|
|
1357
|
+
"--format",
|
|
1358
|
+
"-f",
|
|
1359
|
+
help="Output format (table, json, csv)",
|
|
1360
|
+
autocompletion=complete_output_format,
|
|
1361
|
+
),
|
|
1362
|
+
output: Optional[str] = typer.Option(
|
|
1363
|
+
None, "--output", "-o", help="Output file path"
|
|
1364
|
+
),
|
|
1365
|
+
):
|
|
1366
|
+
"""List schedules that target a specific dataset."""
|
|
1367
|
+
try:
|
|
1368
|
+
cache_rid(dataset_rid)
|
|
1369
|
+
service = DatasetService(profile=profile)
|
|
1370
|
+
|
|
1371
|
+
with SpinnerProgressTracker().track_spinner(
|
|
1372
|
+
f"Fetching schedules for dataset {dataset_rid}..."
|
|
1373
|
+
):
|
|
1374
|
+
schedules = service.get_schedules(dataset_rid)
|
|
1375
|
+
|
|
1376
|
+
formatter.format_schedules(schedules, format, output)
|
|
1377
|
+
|
|
1378
|
+
if output:
|
|
1379
|
+
formatter.print_success(f"Schedules information saved to {output}")
|
|
1380
|
+
|
|
1381
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
1382
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
1383
|
+
raise typer.Exit(1)
|
|
1384
|
+
except Exception as e:
|
|
1385
|
+
formatter.print_error(f"Failed to get schedules: {e}")
|
|
1386
|
+
raise typer.Exit(1)
|
|
1387
|
+
|
|
1388
|
+
|
|
1389
|
+
# Jobs commands
|
|
1390
|
+
@jobs_app.command("list")
|
|
1391
|
+
def list_jobs(
|
|
1392
|
+
dataset_rid: str = typer.Argument(
|
|
1393
|
+
..., help="Dataset Resource Identifier", autocompletion=complete_rid
|
|
1394
|
+
),
|
|
1395
|
+
branch: str = typer.Option("master", "--branch", help="Dataset branch"),
|
|
1396
|
+
profile: Optional[str] = typer.Option(
|
|
1397
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
1398
|
+
),
|
|
1399
|
+
format: str = typer.Option(
|
|
1400
|
+
"table",
|
|
1401
|
+
"--format",
|
|
1402
|
+
"-f",
|
|
1403
|
+
help="Output format (table, json, csv)",
|
|
1404
|
+
autocompletion=complete_output_format,
|
|
1405
|
+
),
|
|
1406
|
+
output: Optional[str] = typer.Option(
|
|
1407
|
+
None, "--output", "-o", help="Output file path"
|
|
1408
|
+
),
|
|
1409
|
+
):
|
|
1410
|
+
"""List jobs for a specific dataset."""
|
|
1411
|
+
try:
|
|
1412
|
+
cache_rid(dataset_rid)
|
|
1413
|
+
service = DatasetService(profile=profile)
|
|
1414
|
+
|
|
1415
|
+
with SpinnerProgressTracker().track_spinner(
|
|
1416
|
+
f"Fetching jobs for dataset {dataset_rid} (branch: {branch})..."
|
|
1417
|
+
):
|
|
1418
|
+
jobs = service.get_jobs(dataset_rid, branch)
|
|
1419
|
+
|
|
1420
|
+
formatter.format_jobs(jobs, format, output)
|
|
1421
|
+
|
|
1422
|
+
if output:
|
|
1423
|
+
formatter.print_success(f"Jobs information saved to {output}")
|
|
1424
|
+
|
|
1425
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
1426
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
1427
|
+
raise typer.Exit(1)
|
|
1428
|
+
except Exception as e:
|
|
1429
|
+
formatter.print_error(f"Failed to get jobs: {e}")
|
|
1430
|
+
raise typer.Exit(1)
|
|
1431
|
+
|
|
1432
|
+
|
|
674
1433
|
# Add subcommands to main app
|
|
675
1434
|
app.add_typer(branches_app, name="branches")
|
|
676
1435
|
app.add_typer(files_app, name="files")
|
|
677
1436
|
app.add_typer(transactions_app, name="transactions")
|
|
678
1437
|
app.add_typer(views_app, name="views")
|
|
1438
|
+
app.add_typer(schema_app, name="schema")
|
|
1439
|
+
app.add_typer(schedules_app, name="schedules")
|
|
1440
|
+
app.add_typer(jobs_app, name="jobs")
|
|
679
1441
|
|
|
680
1442
|
|
|
681
1443
|
@app.callback()
|