pltr-cli 0.5.0__py3-none-any.whl → 0.5.2__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/cli.py +14 -0
- pltr/commands/connectivity.py +432 -0
- pltr/commands/dataset.py +268 -0
- pltr/commands/project.py +440 -0
- pltr/commands/resource.py +499 -0
- pltr/commands/resource_role.py +454 -0
- pltr/commands/space.py +662 -0
- pltr/services/connectivity.py +305 -0
- pltr/services/dataset.py +149 -15
- pltr/services/project.py +232 -0
- pltr/services/resource.py +289 -0
- pltr/services/resource_role.py +321 -0
- pltr/services/space.py +354 -0
- pltr/utils/formatting.py +108 -1
- {pltr_cli-0.5.0.dist-info → pltr_cli-0.5.2.dist-info}/METADATA +101 -2
- {pltr_cli-0.5.0.dist-info → pltr_cli-0.5.2.dist-info}/RECORD +20 -10
- {pltr_cli-0.5.0.dist-info → pltr_cli-0.5.2.dist-info}/WHEEL +0 -0
- {pltr_cli-0.5.0.dist-info → pltr_cli-0.5.2.dist-info}/entry_points.txt +0 -0
- {pltr_cli-0.5.0.dist-info → pltr_cli-0.5.2.dist-info}/licenses/LICENSE +0 -0
pltr/commands/project.py
ADDED
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project management commands for Foundry filesystem.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from typing import Optional, List
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
from rich.table import Table
|
|
9
|
+
|
|
10
|
+
from ..services.project import ProjectService
|
|
11
|
+
from ..utils.formatting import OutputFormatter
|
|
12
|
+
from ..utils.progress import SpinnerProgressTracker
|
|
13
|
+
from ..auth.base import ProfileNotFoundError, MissingCredentialsError
|
|
14
|
+
from ..utils.completion import (
|
|
15
|
+
complete_rid,
|
|
16
|
+
complete_profile,
|
|
17
|
+
complete_output_format,
|
|
18
|
+
cache_rid,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
app = typer.Typer()
|
|
22
|
+
console = Console()
|
|
23
|
+
formatter = OutputFormatter(console)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@app.command("create")
|
|
27
|
+
def create_project(
|
|
28
|
+
name: str = typer.Argument(..., help="Project display name"),
|
|
29
|
+
space_rid: str = typer.Option(
|
|
30
|
+
...,
|
|
31
|
+
"--space-rid",
|
|
32
|
+
"-s",
|
|
33
|
+
help="Space Resource Identifier",
|
|
34
|
+
autocompletion=complete_rid,
|
|
35
|
+
),
|
|
36
|
+
description: Optional[str] = typer.Option(
|
|
37
|
+
None, "--description", "-d", help="Project description"
|
|
38
|
+
),
|
|
39
|
+
organization_rids: Optional[List[str]] = typer.Option(
|
|
40
|
+
None,
|
|
41
|
+
"--organization-rid",
|
|
42
|
+
"-org",
|
|
43
|
+
help="Organization RIDs (can be specified multiple times)",
|
|
44
|
+
),
|
|
45
|
+
profile: Optional[str] = typer.Option(
|
|
46
|
+
None, "--profile", help="Profile name", autocompletion=complete_profile
|
|
47
|
+
),
|
|
48
|
+
format: str = typer.Option(
|
|
49
|
+
"table",
|
|
50
|
+
"--format",
|
|
51
|
+
"-f",
|
|
52
|
+
help="Output format (table, json, csv)",
|
|
53
|
+
autocompletion=complete_output_format,
|
|
54
|
+
),
|
|
55
|
+
):
|
|
56
|
+
"""Create a new project in Foundry."""
|
|
57
|
+
try:
|
|
58
|
+
service = ProjectService(profile=profile)
|
|
59
|
+
|
|
60
|
+
with SpinnerProgressTracker().track_spinner(f"Creating project '{name}'..."):
|
|
61
|
+
project = service.create_project(
|
|
62
|
+
display_name=name,
|
|
63
|
+
space_rid=space_rid,
|
|
64
|
+
description=description,
|
|
65
|
+
organization_rids=organization_rids,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Cache the RID for future completions
|
|
69
|
+
if project.get("rid"):
|
|
70
|
+
cache_rid(project["rid"])
|
|
71
|
+
|
|
72
|
+
formatter.print_success(f"Successfully created project '{name}'")
|
|
73
|
+
formatter.print_info(f"Project RID: {project.get('rid', 'unknown')}")
|
|
74
|
+
|
|
75
|
+
# Format output
|
|
76
|
+
if format == "json":
|
|
77
|
+
formatter.format_dict(project)
|
|
78
|
+
elif format == "csv":
|
|
79
|
+
formatter.format_list([project])
|
|
80
|
+
else:
|
|
81
|
+
_format_project_table(project)
|
|
82
|
+
|
|
83
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
84
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
85
|
+
raise typer.Exit(1)
|
|
86
|
+
except Exception as e:
|
|
87
|
+
formatter.print_error(f"Failed to create project: {e}")
|
|
88
|
+
raise typer.Exit(1)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@app.command("get")
|
|
92
|
+
def get_project(
|
|
93
|
+
project_rid: str = typer.Argument(
|
|
94
|
+
..., help="Project Resource Identifier", autocompletion=complete_rid
|
|
95
|
+
),
|
|
96
|
+
profile: Optional[str] = typer.Option(
|
|
97
|
+
None, "--profile", help="Profile name", autocompletion=complete_profile
|
|
98
|
+
),
|
|
99
|
+
format: str = typer.Option(
|
|
100
|
+
"table",
|
|
101
|
+
"--format",
|
|
102
|
+
"-f",
|
|
103
|
+
help="Output format (table, json, csv)",
|
|
104
|
+
autocompletion=complete_output_format,
|
|
105
|
+
),
|
|
106
|
+
output: Optional[str] = typer.Option(
|
|
107
|
+
None, "--output", "-o", help="Output file path"
|
|
108
|
+
),
|
|
109
|
+
):
|
|
110
|
+
"""Get detailed information about a specific project."""
|
|
111
|
+
try:
|
|
112
|
+
# Cache the RID for future completions
|
|
113
|
+
cache_rid(project_rid)
|
|
114
|
+
|
|
115
|
+
service = ProjectService(profile=profile)
|
|
116
|
+
|
|
117
|
+
with SpinnerProgressTracker().track_spinner(
|
|
118
|
+
f"Fetching project {project_rid}..."
|
|
119
|
+
):
|
|
120
|
+
project = service.get_project(project_rid)
|
|
121
|
+
|
|
122
|
+
# Format output
|
|
123
|
+
if format == "json":
|
|
124
|
+
if output:
|
|
125
|
+
formatter.save_to_file(project, output, "json")
|
|
126
|
+
else:
|
|
127
|
+
formatter.format_dict(project)
|
|
128
|
+
elif format == "csv":
|
|
129
|
+
if output:
|
|
130
|
+
formatter.save_to_file([project], output, "csv")
|
|
131
|
+
else:
|
|
132
|
+
formatter.format_list([project])
|
|
133
|
+
else:
|
|
134
|
+
_format_project_table(project)
|
|
135
|
+
|
|
136
|
+
if output:
|
|
137
|
+
formatter.print_success(f"Project information saved to {output}")
|
|
138
|
+
|
|
139
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
140
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
141
|
+
raise typer.Exit(1)
|
|
142
|
+
except Exception as e:
|
|
143
|
+
formatter.print_error(f"Failed to get project: {e}")
|
|
144
|
+
raise typer.Exit(1)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@app.command("list")
|
|
148
|
+
def list_projects(
|
|
149
|
+
space_rid: Optional[str] = typer.Option(
|
|
150
|
+
None,
|
|
151
|
+
"--space-rid",
|
|
152
|
+
"-s",
|
|
153
|
+
help="Space Resource Identifier to filter by",
|
|
154
|
+
autocompletion=complete_rid,
|
|
155
|
+
),
|
|
156
|
+
profile: Optional[str] = typer.Option(
|
|
157
|
+
None, "--profile", help="Profile name", autocompletion=complete_profile
|
|
158
|
+
),
|
|
159
|
+
format: str = typer.Option(
|
|
160
|
+
"table",
|
|
161
|
+
"--format",
|
|
162
|
+
"-f",
|
|
163
|
+
help="Output format (table, json, csv)",
|
|
164
|
+
autocompletion=complete_output_format,
|
|
165
|
+
),
|
|
166
|
+
output: Optional[str] = typer.Option(
|
|
167
|
+
None, "--output", "-o", help="Output file path"
|
|
168
|
+
),
|
|
169
|
+
page_size: Optional[int] = typer.Option(
|
|
170
|
+
None, "--page-size", help="Number of items per page"
|
|
171
|
+
),
|
|
172
|
+
):
|
|
173
|
+
"""List projects, optionally filtered by space."""
|
|
174
|
+
try:
|
|
175
|
+
service = ProjectService(profile=profile)
|
|
176
|
+
|
|
177
|
+
filter_desc = f" in space {space_rid}" if space_rid else ""
|
|
178
|
+
with SpinnerProgressTracker().track_spinner(
|
|
179
|
+
f"Listing projects{filter_desc}..."
|
|
180
|
+
):
|
|
181
|
+
projects = service.list_projects(space_rid=space_rid, page_size=page_size)
|
|
182
|
+
|
|
183
|
+
if not projects:
|
|
184
|
+
formatter.print_info("No projects found.")
|
|
185
|
+
return
|
|
186
|
+
|
|
187
|
+
# Format output
|
|
188
|
+
if format == "json":
|
|
189
|
+
if output:
|
|
190
|
+
formatter.save_to_file(projects, output, "json")
|
|
191
|
+
else:
|
|
192
|
+
formatter.format_list(projects)
|
|
193
|
+
elif format == "csv":
|
|
194
|
+
if output:
|
|
195
|
+
formatter.save_to_file(projects, output, "csv")
|
|
196
|
+
else:
|
|
197
|
+
formatter.format_list(projects)
|
|
198
|
+
else:
|
|
199
|
+
_format_projects_table(projects)
|
|
200
|
+
|
|
201
|
+
if output:
|
|
202
|
+
formatter.print_success(f"Projects list saved to {output}")
|
|
203
|
+
|
|
204
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
205
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
206
|
+
raise typer.Exit(1)
|
|
207
|
+
except Exception as e:
|
|
208
|
+
formatter.print_error(f"Failed to list projects: {e}")
|
|
209
|
+
raise typer.Exit(1)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
@app.command("update")
|
|
213
|
+
def update_project(
|
|
214
|
+
project_rid: str = typer.Argument(
|
|
215
|
+
..., help="Project Resource Identifier", autocompletion=complete_rid
|
|
216
|
+
),
|
|
217
|
+
name: Optional[str] = typer.Option(
|
|
218
|
+
None, "--name", "-n", help="New project display name"
|
|
219
|
+
),
|
|
220
|
+
description: Optional[str] = typer.Option(
|
|
221
|
+
None, "--description", "-d", help="New project description"
|
|
222
|
+
),
|
|
223
|
+
profile: Optional[str] = typer.Option(
|
|
224
|
+
None, "--profile", help="Profile name", autocompletion=complete_profile
|
|
225
|
+
),
|
|
226
|
+
format: str = typer.Option(
|
|
227
|
+
"table",
|
|
228
|
+
"--format",
|
|
229
|
+
"-f",
|
|
230
|
+
help="Output format (table, json, csv)",
|
|
231
|
+
autocompletion=complete_output_format,
|
|
232
|
+
),
|
|
233
|
+
):
|
|
234
|
+
"""Update project information."""
|
|
235
|
+
try:
|
|
236
|
+
if not name and not description:
|
|
237
|
+
formatter.print_error(
|
|
238
|
+
"At least one field (--name or --description) must be provided"
|
|
239
|
+
)
|
|
240
|
+
raise typer.Exit(1)
|
|
241
|
+
|
|
242
|
+
service = ProjectService(profile=profile)
|
|
243
|
+
|
|
244
|
+
with SpinnerProgressTracker().track_spinner(
|
|
245
|
+
f"Updating project {project_rid}..."
|
|
246
|
+
):
|
|
247
|
+
project = service.update_project(
|
|
248
|
+
project_rid=project_rid,
|
|
249
|
+
display_name=name,
|
|
250
|
+
description=description,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
formatter.print_success(f"Successfully updated project {project_rid}")
|
|
254
|
+
|
|
255
|
+
# Format output
|
|
256
|
+
if format == "json":
|
|
257
|
+
formatter.format_dict(project)
|
|
258
|
+
elif format == "csv":
|
|
259
|
+
formatter.format_list([project])
|
|
260
|
+
else:
|
|
261
|
+
_format_project_table(project)
|
|
262
|
+
|
|
263
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
264
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
265
|
+
raise typer.Exit(1)
|
|
266
|
+
except Exception as e:
|
|
267
|
+
formatter.print_error(f"Failed to update project: {e}")
|
|
268
|
+
raise typer.Exit(1)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
@app.command("delete")
|
|
272
|
+
def delete_project(
|
|
273
|
+
project_rid: str = typer.Argument(
|
|
274
|
+
..., help="Project Resource Identifier", autocompletion=complete_rid
|
|
275
|
+
),
|
|
276
|
+
profile: Optional[str] = typer.Option(
|
|
277
|
+
None, "--profile", help="Profile name", autocompletion=complete_profile
|
|
278
|
+
),
|
|
279
|
+
confirm: bool = typer.Option(False, "--confirm", help="Skip confirmation prompt"),
|
|
280
|
+
):
|
|
281
|
+
"""Delete a project."""
|
|
282
|
+
try:
|
|
283
|
+
if not confirm:
|
|
284
|
+
confirm_delete = typer.confirm(
|
|
285
|
+
f"Are you sure you want to delete project {project_rid}?"
|
|
286
|
+
)
|
|
287
|
+
if not confirm_delete:
|
|
288
|
+
formatter.print_info("Project deletion cancelled.")
|
|
289
|
+
return
|
|
290
|
+
|
|
291
|
+
service = ProjectService(profile=profile)
|
|
292
|
+
|
|
293
|
+
with SpinnerProgressTracker().track_spinner(
|
|
294
|
+
f"Deleting project {project_rid}..."
|
|
295
|
+
):
|
|
296
|
+
service.delete_project(project_rid)
|
|
297
|
+
|
|
298
|
+
formatter.print_success(f"Successfully deleted project {project_rid}")
|
|
299
|
+
|
|
300
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
301
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
302
|
+
raise typer.Exit(1)
|
|
303
|
+
except Exception as e:
|
|
304
|
+
formatter.print_error(f"Failed to delete project: {e}")
|
|
305
|
+
raise typer.Exit(1)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
@app.command("batch-get")
|
|
309
|
+
def get_projects_batch(
|
|
310
|
+
project_rids: List[str] = typer.Argument(
|
|
311
|
+
..., help="Project Resource Identifiers (space-separated)"
|
|
312
|
+
),
|
|
313
|
+
profile: Optional[str] = typer.Option(
|
|
314
|
+
None, "--profile", help="Profile name", autocompletion=complete_profile
|
|
315
|
+
),
|
|
316
|
+
format: str = typer.Option(
|
|
317
|
+
"table",
|
|
318
|
+
"--format",
|
|
319
|
+
"-f",
|
|
320
|
+
help="Output format (table, json, csv)",
|
|
321
|
+
autocompletion=complete_output_format,
|
|
322
|
+
),
|
|
323
|
+
output: Optional[str] = typer.Option(
|
|
324
|
+
None, "--output", "-o", help="Output file path"
|
|
325
|
+
),
|
|
326
|
+
):
|
|
327
|
+
"""Get multiple projects in a single request (max 1000)."""
|
|
328
|
+
try:
|
|
329
|
+
service = ProjectService(profile=profile)
|
|
330
|
+
|
|
331
|
+
with SpinnerProgressTracker().track_spinner(
|
|
332
|
+
f"Fetching {len(project_rids)} projects..."
|
|
333
|
+
):
|
|
334
|
+
projects = service.get_projects_batch(project_rids)
|
|
335
|
+
|
|
336
|
+
# Cache RIDs for future completions
|
|
337
|
+
for project in projects:
|
|
338
|
+
if project.get("rid"):
|
|
339
|
+
cache_rid(project["rid"])
|
|
340
|
+
|
|
341
|
+
# Format output
|
|
342
|
+
if format == "json":
|
|
343
|
+
if output:
|
|
344
|
+
formatter.save_to_file(projects, output, "json")
|
|
345
|
+
else:
|
|
346
|
+
formatter.format_list(projects)
|
|
347
|
+
elif format == "csv":
|
|
348
|
+
if output:
|
|
349
|
+
formatter.save_to_file(projects, output, "csv")
|
|
350
|
+
else:
|
|
351
|
+
formatter.format_list(projects)
|
|
352
|
+
else:
|
|
353
|
+
_format_projects_table(projects)
|
|
354
|
+
|
|
355
|
+
if output:
|
|
356
|
+
formatter.print_success(f"Projects information saved to {output}")
|
|
357
|
+
|
|
358
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
359
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
360
|
+
raise typer.Exit(1)
|
|
361
|
+
except ValueError as e:
|
|
362
|
+
formatter.print_error(f"Invalid request: {e}")
|
|
363
|
+
raise typer.Exit(1)
|
|
364
|
+
except Exception as e:
|
|
365
|
+
formatter.print_error(f"Failed to get projects batch: {e}")
|
|
366
|
+
raise typer.Exit(1)
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def _format_project_table(project: dict):
|
|
370
|
+
"""Format project information as a table."""
|
|
371
|
+
table = Table(
|
|
372
|
+
title="Project Information", show_header=True, header_style="bold cyan"
|
|
373
|
+
)
|
|
374
|
+
table.add_column("Property", style="cyan")
|
|
375
|
+
table.add_column("Value")
|
|
376
|
+
|
|
377
|
+
table.add_row("RID", project.get("rid", "N/A"))
|
|
378
|
+
table.add_row("Display Name", project.get("display_name", "N/A"))
|
|
379
|
+
table.add_row("Description", project.get("description", "N/A"))
|
|
380
|
+
table.add_row("Path", project.get("path", "N/A"))
|
|
381
|
+
table.add_row("Space RID", project.get("space_rid", "N/A"))
|
|
382
|
+
table.add_row("Created By", project.get("created_by", "N/A"))
|
|
383
|
+
table.add_row("Created Time", project.get("created_time", "N/A"))
|
|
384
|
+
table.add_row("Modified By", project.get("modified_by", "N/A"))
|
|
385
|
+
table.add_row("Modified Time", project.get("modified_time", "N/A"))
|
|
386
|
+
table.add_row("Trash Status", project.get("trash_status", "N/A"))
|
|
387
|
+
|
|
388
|
+
console.print(table)
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def _format_projects_table(projects: List[dict]):
|
|
392
|
+
"""Format multiple projects as a table."""
|
|
393
|
+
table = Table(title="Projects", show_header=True, header_style="bold cyan")
|
|
394
|
+
table.add_column("Display Name")
|
|
395
|
+
table.add_column("RID")
|
|
396
|
+
table.add_column("Space RID")
|
|
397
|
+
table.add_column("Created By")
|
|
398
|
+
table.add_column("Created Time")
|
|
399
|
+
|
|
400
|
+
for project in projects:
|
|
401
|
+
table.add_row(
|
|
402
|
+
project.get("display_name", "N/A"),
|
|
403
|
+
project.get("rid", "N/A"),
|
|
404
|
+
project.get("space_rid", "N/A"),
|
|
405
|
+
project.get("created_by", "N/A"),
|
|
406
|
+
project.get("created_time", "N/A"),
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
console.print(table)
|
|
410
|
+
console.print(f"\nTotal: {len(projects)} projects")
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
@app.callback()
|
|
414
|
+
def main():
|
|
415
|
+
"""
|
|
416
|
+
Project operations using foundry-platform-sdk.
|
|
417
|
+
|
|
418
|
+
Manage projects in the Foundry filesystem. Create, retrieve, update, and delete
|
|
419
|
+
projects using Resource Identifiers (RIDs).
|
|
420
|
+
|
|
421
|
+
Examples:
|
|
422
|
+
# Create a project in a space
|
|
423
|
+
pltr project create "My Project" --space-rid ri.compass.main.space.xyz123
|
|
424
|
+
|
|
425
|
+
# List all projects
|
|
426
|
+
pltr project list
|
|
427
|
+
|
|
428
|
+
# List projects in a specific space
|
|
429
|
+
pltr project list --space-rid ri.compass.main.space.xyz123
|
|
430
|
+
|
|
431
|
+
# Get project information
|
|
432
|
+
pltr project get ri.compass.main.project.abc456
|
|
433
|
+
|
|
434
|
+
# Update project
|
|
435
|
+
pltr project update ri.compass.main.project.abc456 --name "Updated Name"
|
|
436
|
+
|
|
437
|
+
# Delete project
|
|
438
|
+
pltr project delete ri.compass.main.project.abc456
|
|
439
|
+
"""
|
|
440
|
+
pass
|