pltr-cli 0.1.2__py3-none-any.whl → 0.2.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/__main__.py ADDED
@@ -0,0 +1,28 @@
1
+ """Main entry point for pltr CLI."""
2
+
3
+ import os
4
+ import sys
5
+
6
+ # Handle shell completion before importing the main app
7
+ if "_PLTR_COMPLETE" in os.environ:
8
+ # Import Click's completion handling
9
+ from click.shell_completion import shell_complete
10
+ import typer
11
+ from pltr.cli import app
12
+
13
+ # Convert Typer app to Click command
14
+ click_app = typer.main.get_command(app)
15
+
16
+ # Get the completion instruction from environment
17
+ complete_var = "_PLTR_COMPLETE"
18
+ instruction = os.environ.get(complete_var, "")
19
+
20
+ # Run Click's completion
21
+ exit_code = shell_complete(click_app, {}, "pltr", complete_var, instruction)
22
+ sys.exit(exit_code)
23
+
24
+ # Normal CLI execution
25
+ from pltr.cli import app
26
+
27
+ if __name__ == "__main__":
28
+ app()
pltr/cli.py CHANGED
@@ -6,7 +6,16 @@ import typer
6
6
  from typing_extensions import Annotated
7
7
 
8
8
  from pltr import __version__
9
- from pltr.commands import configure, verify, dataset
9
+ from pltr.commands import (
10
+ configure,
11
+ verify,
12
+ dataset,
13
+ ontology,
14
+ sql,
15
+ admin,
16
+ shell,
17
+ completion,
18
+ )
10
19
 
11
20
  app = typer.Typer(
12
21
  name="pltr",
@@ -18,6 +27,15 @@ app = typer.Typer(
18
27
  app.add_typer(configure.app, name="configure", help="Manage authentication profiles")
19
28
  app.add_typer(verify.app, name="verify", help="Verify authentication")
20
29
  app.add_typer(dataset.app, name="dataset", help="Manage datasets")
30
+ app.add_typer(ontology.app, name="ontology", help="Ontology operations")
31
+ app.add_typer(sql.app, name="sql", help="Execute SQL queries")
32
+ app.add_typer(
33
+ admin.app,
34
+ name="admin",
35
+ help="Admin operations for user, group, and organization management",
36
+ )
37
+ app.add_typer(shell.shell_app, name="shell", help="Interactive shell mode")
38
+ app.add_typer(completion.app, name="completion", help="Manage shell completions")
21
39
 
22
40
 
23
41
  def version_callback(value: bool):
pltr/commands/admin.py ADDED
@@ -0,0 +1,530 @@
1
+ """
2
+ Admin commands for the pltr CLI.
3
+ Provides commands for user, group, role, and organization management.
4
+ """
5
+
6
+ from pathlib import Path
7
+ from typing import Optional
8
+
9
+ import typer
10
+ from rich.console import Console
11
+
12
+ from ..services.admin import AdminService
13
+ from ..utils.formatting import OutputFormatter
14
+ from ..utils.progress import SpinnerProgressTracker
15
+
16
+ # Create the main admin app
17
+ app = typer.Typer(
18
+ name="admin", help="Admin operations for user, group, and organization management"
19
+ )
20
+
21
+ # Create sub-apps for different admin categories
22
+ user_app = typer.Typer(name="user", help="User management operations")
23
+ group_app = typer.Typer(name="group", help="Group management operations")
24
+ role_app = typer.Typer(name="role", help="Role management operations")
25
+ org_app = typer.Typer(name="org", help="Organization management operations")
26
+
27
+ # Add sub-apps to main admin app
28
+ app.add_typer(user_app, name="user")
29
+ app.add_typer(group_app, name="group")
30
+ app.add_typer(role_app, name="role")
31
+ app.add_typer(org_app, name="org")
32
+
33
+
34
+ # User Management Commands
35
+ @user_app.command("list")
36
+ def list_users(
37
+ profile: Optional[str] = typer.Option(
38
+ None, "--profile", help="Auth profile to use"
39
+ ),
40
+ output_format: str = typer.Option(
41
+ "table", "--format", help="Output format (table, json, csv)"
42
+ ),
43
+ output_file: Optional[Path] = typer.Option(
44
+ None, "--output", help="Save results to file"
45
+ ),
46
+ page_size: Optional[int] = typer.Option(
47
+ None, "--page-size", help="Number of users per page"
48
+ ),
49
+ page_token: Optional[str] = typer.Option(
50
+ None, "--page-token", help="Pagination token from previous response"
51
+ ),
52
+ ) -> None:
53
+ """List all users in the organization."""
54
+ console = Console()
55
+ formatter = OutputFormatter()
56
+
57
+ try:
58
+ service = AdminService(profile=profile)
59
+
60
+ with SpinnerProgressTracker().track_spinner("Fetching users..."):
61
+ result = service.list_users(page_size=page_size, page_token=page_token)
62
+
63
+ # Format and display results
64
+ if output_file:
65
+ formatter.save_to_file(result, output_file, output_format)
66
+ console.print(f"Results saved to {output_file}")
67
+ else:
68
+ formatter.display(result, output_format)
69
+
70
+ except Exception as e:
71
+ console.print(f"[red]Error:[/red] {e}")
72
+ raise typer.Exit(code=1)
73
+
74
+
75
+ @user_app.command("get")
76
+ def get_user(
77
+ user_id: str = typer.Argument(..., help="User ID or RID"),
78
+ profile: Optional[str] = typer.Option(
79
+ None, "--profile", help="Auth profile to use"
80
+ ),
81
+ output_format: str = typer.Option(
82
+ "table", "--format", help="Output format (table, json, csv)"
83
+ ),
84
+ output_file: Optional[Path] = typer.Option(
85
+ None, "--output", help="Save results to file"
86
+ ),
87
+ ) -> None:
88
+ """Get information about a specific user."""
89
+ console = Console()
90
+ formatter = OutputFormatter()
91
+
92
+ try:
93
+ service = AdminService(profile=profile)
94
+
95
+ with SpinnerProgressTracker().track_spinner(f"Fetching user {user_id}..."):
96
+ result = service.get_user(user_id)
97
+
98
+ # Format and display results
99
+ if output_file:
100
+ formatter.save_to_file(result, output_file, output_format)
101
+ console.print(f"Results saved to {output_file}")
102
+ else:
103
+ formatter.display(result, output_format)
104
+
105
+ except Exception as e:
106
+ console.print(f"[red]Error:[/red] {e}")
107
+ raise typer.Exit(code=1)
108
+
109
+
110
+ @user_app.command("current")
111
+ def get_current_user(
112
+ profile: Optional[str] = typer.Option(
113
+ None, "--profile", help="Auth profile to use"
114
+ ),
115
+ output_format: str = typer.Option(
116
+ "table", "--format", help="Output format (table, json, csv)"
117
+ ),
118
+ output_file: Optional[Path] = typer.Option(
119
+ None, "--output", help="Save results to file"
120
+ ),
121
+ ) -> None:
122
+ """Get information about the current authenticated user."""
123
+ console = Console()
124
+ formatter = OutputFormatter()
125
+
126
+ try:
127
+ service = AdminService(profile=profile)
128
+
129
+ with SpinnerProgressTracker().track_spinner("Fetching current user info..."):
130
+ result = service.get_current_user()
131
+
132
+ # Format and display results
133
+ if output_file:
134
+ formatter.save_to_file(result, output_file, output_format)
135
+ console.print(f"Results saved to {output_file}")
136
+ else:
137
+ formatter.display(result, output_format)
138
+
139
+ except Exception as e:
140
+ console.print(f"[red]Error:[/red] {e}")
141
+ raise typer.Exit(code=1)
142
+
143
+
144
+ @user_app.command("search")
145
+ def search_users(
146
+ query: str = typer.Argument(..., help="Search query string"),
147
+ profile: Optional[str] = typer.Option(
148
+ None, "--profile", help="Auth profile to use"
149
+ ),
150
+ output_format: str = typer.Option(
151
+ "table", "--format", help="Output format (table, json, csv)"
152
+ ),
153
+ output_file: Optional[Path] = typer.Option(
154
+ None, "--output", help="Save results to file"
155
+ ),
156
+ page_size: Optional[int] = typer.Option(
157
+ None, "--page-size", help="Number of users per page"
158
+ ),
159
+ page_token: Optional[str] = typer.Option(
160
+ None, "--page-token", help="Pagination token from previous response"
161
+ ),
162
+ ) -> None:
163
+ """Search for users by query string."""
164
+ console = Console()
165
+ formatter = OutputFormatter()
166
+
167
+ try:
168
+ service = AdminService(profile=profile)
169
+
170
+ with SpinnerProgressTracker().track_spinner(
171
+ f"Searching users for '{query}'..."
172
+ ):
173
+ result = service.search_users(
174
+ query=query, page_size=page_size, page_token=page_token
175
+ )
176
+
177
+ # Format and display results
178
+ if output_file:
179
+ formatter.save_to_file(result, output_file, output_format)
180
+ console.print(f"Results saved to {output_file}")
181
+ else:
182
+ formatter.display(result, output_format)
183
+
184
+ except Exception as e:
185
+ console.print(f"[red]Error:[/red] {e}")
186
+ raise typer.Exit(code=1)
187
+
188
+
189
+ @user_app.command("markings")
190
+ def get_user_markings(
191
+ user_id: str = typer.Argument(..., help="User ID or RID"),
192
+ profile: Optional[str] = typer.Option(
193
+ None, "--profile", help="Auth profile to use"
194
+ ),
195
+ output_format: str = typer.Option(
196
+ "table", "--format", help="Output format (table, json, csv)"
197
+ ),
198
+ output_file: Optional[Path] = typer.Option(
199
+ None, "--output", help="Save results to file"
200
+ ),
201
+ ) -> None:
202
+ """Get markings/permissions for a specific user."""
203
+ console = Console()
204
+ formatter = OutputFormatter()
205
+
206
+ try:
207
+ service = AdminService(profile=profile)
208
+
209
+ with SpinnerProgressTracker().track_spinner(
210
+ f"Fetching markings for user {user_id}..."
211
+ ):
212
+ result = service.get_user_markings(user_id)
213
+
214
+ # Format and display results
215
+ if output_file:
216
+ formatter.save_to_file(result, output_file, output_format)
217
+ console.print(f"Results saved to {output_file}")
218
+ else:
219
+ formatter.display(result, output_format)
220
+
221
+ except Exception as e:
222
+ console.print(f"[red]Error:[/red] {e}")
223
+ raise typer.Exit(code=1)
224
+
225
+
226
+ @user_app.command("revoke-tokens")
227
+ def revoke_user_tokens(
228
+ user_id: str = typer.Argument(..., help="User ID or RID"),
229
+ profile: Optional[str] = typer.Option(
230
+ None, "--profile", help="Auth profile to use"
231
+ ),
232
+ confirm: bool = typer.Option(False, "--confirm", help="Skip confirmation prompt"),
233
+ ) -> None:
234
+ """Revoke all tokens for a specific user."""
235
+ console = Console()
236
+
237
+ # Confirmation prompt
238
+ if not confirm:
239
+ user_confirm = typer.confirm(
240
+ f"Are you sure you want to revoke all tokens for user {user_id}?"
241
+ )
242
+ if not user_confirm:
243
+ console.print("Operation cancelled.")
244
+ return
245
+
246
+ try:
247
+ service = AdminService(profile=profile)
248
+
249
+ with SpinnerProgressTracker().track_spinner(
250
+ f"Revoking tokens for user {user_id}..."
251
+ ):
252
+ result = service.revoke_user_tokens(user_id)
253
+
254
+ console.print(f"[green]{result['message']}[/green]")
255
+
256
+ except Exception as e:
257
+ console.print(f"[red]Error:[/red] {e}")
258
+ raise typer.Exit(code=1)
259
+
260
+
261
+ # Group Management Commands
262
+ @group_app.command("list")
263
+ def list_groups(
264
+ profile: Optional[str] = typer.Option(
265
+ None, "--profile", help="Auth profile to use"
266
+ ),
267
+ output_format: str = typer.Option(
268
+ "table", "--format", help="Output format (table, json, csv)"
269
+ ),
270
+ output_file: Optional[Path] = typer.Option(
271
+ None, "--output", help="Save results to file"
272
+ ),
273
+ page_size: Optional[int] = typer.Option(
274
+ None, "--page-size", help="Number of groups per page"
275
+ ),
276
+ page_token: Optional[str] = typer.Option(
277
+ None, "--page-token", help="Pagination token from previous response"
278
+ ),
279
+ ) -> None:
280
+ """List all groups in the organization."""
281
+ console = Console()
282
+ formatter = OutputFormatter()
283
+
284
+ try:
285
+ service = AdminService(profile=profile)
286
+
287
+ with SpinnerProgressTracker().track_spinner("Fetching groups..."):
288
+ result = service.list_groups(page_size=page_size, page_token=page_token)
289
+
290
+ # Format and display results
291
+ if output_file:
292
+ formatter.save_to_file(result, output_file, output_format)
293
+ console.print(f"Results saved to {output_file}")
294
+ else:
295
+ formatter.display(result, output_format)
296
+
297
+ except Exception as e:
298
+ console.print(f"[red]Error:[/red] {e}")
299
+ raise typer.Exit(code=1)
300
+
301
+
302
+ @group_app.command("get")
303
+ def get_group(
304
+ group_id: str = typer.Argument(..., help="Group ID or RID"),
305
+ profile: Optional[str] = typer.Option(
306
+ None, "--profile", help="Auth profile to use"
307
+ ),
308
+ output_format: str = typer.Option(
309
+ "table", "--format", help="Output format (table, json, csv)"
310
+ ),
311
+ output_file: Optional[Path] = typer.Option(
312
+ None, "--output", help="Save results to file"
313
+ ),
314
+ ) -> None:
315
+ """Get information about a specific group."""
316
+ console = Console()
317
+ formatter = OutputFormatter()
318
+
319
+ try:
320
+ service = AdminService(profile=profile)
321
+
322
+ with SpinnerProgressTracker().track_spinner(f"Fetching group {group_id}..."):
323
+ result = service.get_group(group_id)
324
+
325
+ # Format and display results
326
+ if output_file:
327
+ formatter.save_to_file(result, output_file, output_format)
328
+ console.print(f"Results saved to {output_file}")
329
+ else:
330
+ formatter.display(result, output_format)
331
+
332
+ except Exception as e:
333
+ console.print(f"[red]Error:[/red] {e}")
334
+ raise typer.Exit(code=1)
335
+
336
+
337
+ @group_app.command("search")
338
+ def search_groups(
339
+ query: str = typer.Argument(..., help="Search query string"),
340
+ profile: Optional[str] = typer.Option(
341
+ None, "--profile", help="Auth profile to use"
342
+ ),
343
+ output_format: str = typer.Option(
344
+ "table", "--format", help="Output format (table, json, csv)"
345
+ ),
346
+ output_file: Optional[Path] = typer.Option(
347
+ None, "--output", help="Save results to file"
348
+ ),
349
+ page_size: Optional[int] = typer.Option(
350
+ None, "--page-size", help="Number of groups per page"
351
+ ),
352
+ page_token: Optional[str] = typer.Option(
353
+ None, "--page-token", help="Pagination token from previous response"
354
+ ),
355
+ ) -> None:
356
+ """Search for groups by query string."""
357
+ console = Console()
358
+ formatter = OutputFormatter()
359
+
360
+ try:
361
+ service = AdminService(profile=profile)
362
+
363
+ with SpinnerProgressTracker().track_spinner(
364
+ f"Searching groups for '{query}'..."
365
+ ):
366
+ result = service.search_groups(
367
+ query=query, page_size=page_size, page_token=page_token
368
+ )
369
+
370
+ # Format and display results
371
+ if output_file:
372
+ formatter.save_to_file(result, output_file, output_format)
373
+ console.print(f"Results saved to {output_file}")
374
+ else:
375
+ formatter.display(result, output_format)
376
+
377
+ except Exception as e:
378
+ console.print(f"[red]Error:[/red] {e}")
379
+ raise typer.Exit(code=1)
380
+
381
+
382
+ @group_app.command("create")
383
+ def create_group(
384
+ name: str = typer.Argument(..., help="Group name"),
385
+ profile: Optional[str] = typer.Option(
386
+ None, "--profile", help="Auth profile to use"
387
+ ),
388
+ description: Optional[str] = typer.Option(
389
+ None, "--description", help="Group description"
390
+ ),
391
+ organization_rid: Optional[str] = typer.Option(
392
+ None, "--org-rid", help="Organization RID"
393
+ ),
394
+ output_format: str = typer.Option(
395
+ "table", "--format", help="Output format (table, json, csv)"
396
+ ),
397
+ output_file: Optional[Path] = typer.Option(
398
+ None, "--output", help="Save results to file"
399
+ ),
400
+ ) -> None:
401
+ """Create a new group."""
402
+ console = Console()
403
+ formatter = OutputFormatter()
404
+
405
+ try:
406
+ service = AdminService(profile=profile)
407
+
408
+ with SpinnerProgressTracker().track_spinner(f"Creating group '{name}'..."):
409
+ result = service.create_group(
410
+ name=name, description=description, organization_rid=organization_rid
411
+ )
412
+
413
+ # Format and display results
414
+ if output_file:
415
+ formatter.save_to_file(result, output_file, output_format)
416
+ console.print(f"Results saved to {output_file}")
417
+ else:
418
+ formatter.display(result, output_format)
419
+ console.print(f"[green]Group '{name}' created successfully[/green]")
420
+
421
+ except Exception as e:
422
+ console.print(f"[red]Error:[/red] {e}")
423
+ raise typer.Exit(code=1)
424
+
425
+
426
+ @group_app.command("delete")
427
+ def delete_group(
428
+ group_id: str = typer.Argument(..., help="Group ID or RID"),
429
+ profile: Optional[str] = typer.Option(
430
+ None, "--profile", help="Auth profile to use"
431
+ ),
432
+ confirm: bool = typer.Option(False, "--confirm", help="Skip confirmation prompt"),
433
+ ) -> None:
434
+ """Delete a specific group."""
435
+ console = Console()
436
+
437
+ # Confirmation prompt
438
+ if not confirm:
439
+ user_confirm = typer.confirm(
440
+ f"Are you sure you want to delete group {group_id}?"
441
+ )
442
+ if not user_confirm:
443
+ console.print("Operation cancelled.")
444
+ return
445
+
446
+ try:
447
+ service = AdminService(profile=profile)
448
+
449
+ with SpinnerProgressTracker().track_spinner(f"Deleting group {group_id}..."):
450
+ result = service.delete_group(group_id)
451
+
452
+ console.print(f"[green]{result['message']}[/green]")
453
+
454
+ except Exception as e:
455
+ console.print(f"[red]Error:[/red] {e}")
456
+ raise typer.Exit(code=1)
457
+
458
+
459
+ # Role Management Commands
460
+ @role_app.command("get")
461
+ def get_role(
462
+ role_id: str = typer.Argument(..., help="Role ID or RID"),
463
+ profile: Optional[str] = typer.Option(
464
+ None, "--profile", help="Auth profile to use"
465
+ ),
466
+ output_format: str = typer.Option(
467
+ "table", "--format", help="Output format (table, json, csv)"
468
+ ),
469
+ output_file: Optional[Path] = typer.Option(
470
+ None, "--output", help="Save results to file"
471
+ ),
472
+ ) -> None:
473
+ """Get information about a specific role."""
474
+ console = Console()
475
+ formatter = OutputFormatter()
476
+
477
+ try:
478
+ service = AdminService(profile=profile)
479
+
480
+ with SpinnerProgressTracker().track_spinner(f"Fetching role {role_id}..."):
481
+ result = service.get_role(role_id)
482
+
483
+ # Format and display results
484
+ if output_file:
485
+ formatter.save_to_file(result, output_file, output_format)
486
+ console.print(f"Results saved to {output_file}")
487
+ else:
488
+ formatter.display(result, output_format)
489
+
490
+ except Exception as e:
491
+ console.print(f"[red]Error:[/red] {e}")
492
+ raise typer.Exit(code=1)
493
+
494
+
495
+ # Organization Management Commands
496
+ @org_app.command("get")
497
+ def get_organization(
498
+ organization_id: str = typer.Argument(..., help="Organization ID or RID"),
499
+ profile: Optional[str] = typer.Option(
500
+ None, "--profile", help="Auth profile to use"
501
+ ),
502
+ output_format: str = typer.Option(
503
+ "table", "--format", help="Output format (table, json, csv)"
504
+ ),
505
+ output_file: Optional[Path] = typer.Option(
506
+ None, "--output", help="Save results to file"
507
+ ),
508
+ ) -> None:
509
+ """Get information about a specific organization."""
510
+ console = Console()
511
+ formatter = OutputFormatter()
512
+
513
+ try:
514
+ service = AdminService(profile=profile)
515
+
516
+ with SpinnerProgressTracker().track_spinner(
517
+ f"Fetching organization {organization_id}..."
518
+ ):
519
+ result = service.get_organization(organization_id)
520
+
521
+ # Format and display results
522
+ if output_file:
523
+ formatter.save_to_file(result, output_file, output_format)
524
+ console.print(f"Results saved to {output_file}")
525
+ else:
526
+ formatter.display(result, output_format)
527
+
528
+ except Exception as e:
529
+ console.print(f"[red]Error:[/red] {e}")
530
+ raise typer.Exit(code=1)