pltr-cli 0.11.0__py3-none-any.whl → 0.13.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.
Files changed (46) hide show
  1. pltr/__init__.py +1 -1
  2. pltr/cli.py +40 -0
  3. pltr/commands/admin.py +565 -11
  4. pltr/commands/aip_agents.py +333 -0
  5. pltr/commands/connectivity.py +309 -1
  6. pltr/commands/cp.py +103 -0
  7. pltr/commands/dataset.py +104 -4
  8. pltr/commands/functions.py +503 -0
  9. pltr/commands/language_models.py +515 -0
  10. pltr/commands/mediasets.py +176 -0
  11. pltr/commands/models.py +362 -0
  12. pltr/commands/ontology.py +44 -13
  13. pltr/commands/orchestration.py +167 -11
  14. pltr/commands/project.py +231 -22
  15. pltr/commands/resource.py +416 -17
  16. pltr/commands/space.py +25 -303
  17. pltr/commands/sql.py +54 -7
  18. pltr/commands/streams.py +616 -0
  19. pltr/commands/third_party_applications.py +82 -0
  20. pltr/services/admin.py +331 -3
  21. pltr/services/aip_agents.py +147 -0
  22. pltr/services/base.py +104 -1
  23. pltr/services/connectivity.py +139 -0
  24. pltr/services/copy.py +391 -0
  25. pltr/services/dataset.py +77 -4
  26. pltr/services/folder.py +6 -1
  27. pltr/services/functions.py +223 -0
  28. pltr/services/language_models.py +281 -0
  29. pltr/services/mediasets.py +144 -9
  30. pltr/services/models.py +179 -0
  31. pltr/services/ontology.py +48 -1
  32. pltr/services/orchestration.py +133 -1
  33. pltr/services/project.py +213 -39
  34. pltr/services/resource.py +229 -60
  35. pltr/services/space.py +24 -175
  36. pltr/services/sql.py +44 -20
  37. pltr/services/streams.py +290 -0
  38. pltr/services/third_party_applications.py +53 -0
  39. pltr/utils/formatting.py +195 -1
  40. pltr/utils/pagination.py +325 -0
  41. {pltr_cli-0.11.0.dist-info → pltr_cli-0.13.0.dist-info}/METADATA +55 -4
  42. pltr_cli-0.13.0.dist-info/RECORD +70 -0
  43. {pltr_cli-0.11.0.dist-info → pltr_cli-0.13.0.dist-info}/WHEEL +1 -1
  44. pltr_cli-0.11.0.dist-info/RECORD +0 -55
  45. {pltr_cli-0.11.0.dist-info → pltr_cli-0.13.0.dist-info}/entry_points.txt +0 -0
  46. {pltr_cli-0.11.0.dist-info → pltr_cli-0.13.0.dist-info}/licenses/LICENSE +0 -0
pltr/commands/resource.py CHANGED
@@ -409,17 +409,195 @@ def get_resource_metadata(
409
409
  raise typer.Exit(1)
410
410
 
411
411
 
412
- @app.command("move")
413
- def move_resource(
412
+ # ==================== Trash Operations ====================
413
+
414
+
415
+ @app.command("delete")
416
+ def delete_resource(
417
+ resource_rid: str = typer.Argument(
418
+ ..., help="Resource Identifier", autocompletion=complete_rid
419
+ ),
420
+ profile: Optional[str] = typer.Option(
421
+ None, "--profile", help="Profile name", autocompletion=complete_profile
422
+ ),
423
+ force: bool = typer.Option(False, "--force", "-f", help="Skip confirmation prompt"),
424
+ ):
425
+ """Move a resource to trash."""
426
+ try:
427
+ if not force:
428
+ confirm = typer.confirm(
429
+ f"Are you sure you want to move resource {resource_rid} to trash?"
430
+ )
431
+ if not confirm:
432
+ formatter.print_info("Operation cancelled.")
433
+ return
434
+
435
+ service = ResourceService(profile=profile)
436
+
437
+ with SpinnerProgressTracker().track_spinner(
438
+ f"Moving resource {resource_rid} to trash..."
439
+ ):
440
+ service.delete_resource(resource_rid)
441
+
442
+ formatter.print_success(f"Successfully moved resource {resource_rid} to trash")
443
+
444
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
445
+ formatter.print_error(f"Authentication error: {e}")
446
+ raise typer.Exit(1)
447
+ except Exception as e:
448
+ formatter.print_error(f"Failed to delete resource: {e}")
449
+ raise typer.Exit(1)
450
+
451
+
452
+ @app.command("restore")
453
+ def restore_resource(
454
+ resource_rid: str = typer.Argument(
455
+ ..., help="Resource Identifier", autocompletion=complete_rid
456
+ ),
457
+ profile: Optional[str] = typer.Option(
458
+ None, "--profile", help="Profile name", autocompletion=complete_profile
459
+ ),
460
+ ):
461
+ """Restore a resource from trash."""
462
+ try:
463
+ service = ResourceService(profile=profile)
464
+
465
+ with SpinnerProgressTracker().track_spinner(
466
+ f"Restoring resource {resource_rid} from trash..."
467
+ ):
468
+ service.restore_resource(resource_rid)
469
+
470
+ formatter.print_success(
471
+ f"Successfully restored resource {resource_rid} from trash"
472
+ )
473
+
474
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
475
+ formatter.print_error(f"Authentication error: {e}")
476
+ raise typer.Exit(1)
477
+ except Exception as e:
478
+ formatter.print_error(f"Failed to restore resource: {e}")
479
+ raise typer.Exit(1)
480
+
481
+
482
+ @app.command("permanently-delete")
483
+ def permanently_delete_resource(
414
484
  resource_rid: str = typer.Argument(
415
485
  ..., help="Resource Identifier", autocompletion=complete_rid
416
486
  ),
417
- target_folder_rid: str = typer.Option(
487
+ profile: Optional[str] = typer.Option(
488
+ None, "--profile", help="Profile name", autocompletion=complete_profile
489
+ ),
490
+ force: bool = typer.Option(False, "--force", "-f", help="Skip confirmation prompt"),
491
+ ):
492
+ """Permanently delete a resource from trash. This action is irreversible."""
493
+ try:
494
+ if not force:
495
+ confirm = typer.confirm(
496
+ f"Are you sure you want to PERMANENTLY delete resource {resource_rid}? "
497
+ "This action cannot be undone!"
498
+ )
499
+ if not confirm:
500
+ formatter.print_info("Operation cancelled.")
501
+ return
502
+
503
+ service = ResourceService(profile=profile)
504
+
505
+ with SpinnerProgressTracker().track_spinner(
506
+ f"Permanently deleting resource {resource_rid}..."
507
+ ):
508
+ service.permanently_delete_resource(resource_rid)
509
+
510
+ formatter.print_success(
511
+ f"Successfully permanently deleted resource {resource_rid}"
512
+ )
513
+
514
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
515
+ formatter.print_error(f"Authentication error: {e}")
516
+ raise typer.Exit(1)
517
+ except Exception as e:
518
+ formatter.print_error(f"Failed to permanently delete resource: {e}")
519
+ raise typer.Exit(1)
520
+
521
+
522
+ # ==================== Markings Operations ====================
523
+
524
+
525
+ @app.command("add-markings")
526
+ def add_markings(
527
+ resource_rid: str = typer.Argument(
528
+ ..., help="Resource Identifier", autocompletion=complete_rid
529
+ ),
530
+ marking_ids: List[str] = typer.Option(
418
531
  ...,
419
- "--target-folder",
420
- "-t",
421
- help="Target folder Resource Identifier",
422
- autocompletion=complete_rid,
532
+ "--marking",
533
+ "-m",
534
+ help="Marking identifier(s) to add (can specify multiple)",
535
+ ),
536
+ profile: Optional[str] = typer.Option(
537
+ None, "--profile", help="Profile name", autocompletion=complete_profile
538
+ ),
539
+ ):
540
+ """Add markings to a resource."""
541
+ try:
542
+ service = ResourceService(profile=profile)
543
+
544
+ with SpinnerProgressTracker().track_spinner(
545
+ f"Adding {len(marking_ids)} marking(s) to resource {resource_rid}..."
546
+ ):
547
+ service.add_markings(resource_rid, marking_ids)
548
+
549
+ formatter.print_success(
550
+ f"Successfully added {len(marking_ids)} marking(s) to resource {resource_rid}"
551
+ )
552
+
553
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
554
+ formatter.print_error(f"Authentication error: {e}")
555
+ raise typer.Exit(1)
556
+ except Exception as e:
557
+ formatter.print_error(f"Failed to add markings: {e}")
558
+ raise typer.Exit(1)
559
+
560
+
561
+ @app.command("remove-markings")
562
+ def remove_markings(
563
+ resource_rid: str = typer.Argument(
564
+ ..., help="Resource Identifier", autocompletion=complete_rid
565
+ ),
566
+ marking_ids: List[str] = typer.Option(
567
+ ...,
568
+ "--marking",
569
+ "-m",
570
+ help="Marking identifier(s) to remove (can specify multiple)",
571
+ ),
572
+ profile: Optional[str] = typer.Option(
573
+ None, "--profile", help="Profile name", autocompletion=complete_profile
574
+ ),
575
+ ):
576
+ """Remove markings from a resource."""
577
+ try:
578
+ service = ResourceService(profile=profile)
579
+
580
+ with SpinnerProgressTracker().track_spinner(
581
+ f"Removing {len(marking_ids)} marking(s) from resource {resource_rid}..."
582
+ ):
583
+ service.remove_markings(resource_rid, marking_ids)
584
+
585
+ formatter.print_success(
586
+ f"Successfully removed {len(marking_ids)} marking(s) from resource {resource_rid}"
587
+ )
588
+
589
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
590
+ formatter.print_error(f"Authentication error: {e}")
591
+ raise typer.Exit(1)
592
+ except Exception as e:
593
+ formatter.print_error(f"Failed to remove markings: {e}")
594
+ raise typer.Exit(1)
595
+
596
+
597
+ @app.command("list-markings")
598
+ def list_markings(
599
+ resource_rid: str = typer.Argument(
600
+ ..., help="Resource Identifier", autocompletion=complete_rid
423
601
  ),
424
602
  profile: Optional[str] = typer.Option(
425
603
  None, "--profile", help="Profile name", autocompletion=complete_profile
@@ -431,31 +609,175 @@ def move_resource(
431
609
  help="Output format (table, json, csv)",
432
610
  autocompletion=complete_output_format,
433
611
  ),
612
+ output: Optional[str] = typer.Option(
613
+ None, "--output", "-o", help="Output file path"
614
+ ),
615
+ page_size: Optional[int] = typer.Option(
616
+ None, "--page-size", help="Number of items per page"
617
+ ),
434
618
  ):
435
- """Move a resource to a different folder."""
619
+ """List markings directly applied to a resource."""
436
620
  try:
437
621
  service = ResourceService(profile=profile)
438
622
 
439
623
  with SpinnerProgressTracker().track_spinner(
440
- f"Moving resource {resource_rid} to {target_folder_rid}..."
624
+ f"Fetching markings for resource {resource_rid}..."
441
625
  ):
442
- resource = service.move_resource(resource_rid, target_folder_rid)
626
+ markings = service.list_markings(resource_rid, page_size=page_size)
443
627
 
444
- formatter.print_success(f"Successfully moved resource to {target_folder_rid}")
628
+ if not markings:
629
+ formatter.print_info("No markings found on this resource.")
630
+ return
445
631
 
446
632
  # Format output
447
633
  if format == "json":
448
- formatter.format_dict(resource)
634
+ if output:
635
+ formatter.save_to_file(markings, output, "json")
636
+ else:
637
+ formatter.format_list(markings)
449
638
  elif format == "csv":
450
- formatter.format_list([resource])
639
+ if output:
640
+ formatter.save_to_file(markings, output, "csv")
641
+ else:
642
+ formatter.format_list(markings)
451
643
  else:
452
- _format_resource_table(resource)
644
+ _format_markings_table(markings)
645
+
646
+ if output:
647
+ formatter.print_success(f"Markings list saved to {output}")
648
+
649
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
650
+ formatter.print_error(f"Authentication error: {e}")
651
+ raise typer.Exit(1)
652
+ except Exception as e:
653
+ formatter.print_error(f"Failed to list markings: {e}")
654
+ raise typer.Exit(1)
655
+
656
+
657
+ # ==================== Access & Batch Operations ====================
658
+
659
+
660
+ @app.command("access-requirements")
661
+ def get_access_requirements(
662
+ resource_rid: str = typer.Argument(
663
+ ..., help="Resource Identifier", autocompletion=complete_rid
664
+ ),
665
+ profile: Optional[str] = typer.Option(
666
+ None, "--profile", help="Profile name", autocompletion=complete_profile
667
+ ),
668
+ format: str = typer.Option(
669
+ "table",
670
+ "--format",
671
+ "-f",
672
+ help="Output format (table, json, csv)",
673
+ autocompletion=complete_output_format,
674
+ ),
675
+ output: Optional[str] = typer.Option(
676
+ None, "--output", "-o", help="Output file path"
677
+ ),
678
+ ):
679
+ """Get access requirements (organizations and markings) for a resource."""
680
+ try:
681
+ service = ResourceService(profile=profile)
682
+
683
+ with SpinnerProgressTracker().track_spinner(
684
+ f"Fetching access requirements for resource {resource_rid}..."
685
+ ):
686
+ requirements = service.get_access_requirements(resource_rid)
687
+
688
+ # Format output
689
+ if format == "json":
690
+ if output:
691
+ formatter.save_to_file(requirements, output, "json")
692
+ else:
693
+ formatter.format_dict(requirements)
694
+ elif format == "csv":
695
+ # Flatten for CSV output
696
+ flat_data = []
697
+ for org in requirements.get("organizations", []):
698
+ flat_data.append({"type": "organization", **org})
699
+ for marking in requirements.get("markings", []):
700
+ flat_data.append({"type": "marking", **marking})
701
+ if output:
702
+ formatter.save_to_file(flat_data, output, "csv")
703
+ else:
704
+ formatter.format_list(flat_data)
705
+ else:
706
+ _format_access_requirements_table(requirements)
707
+
708
+ if output:
709
+ formatter.print_success(f"Access requirements saved to {output}")
710
+
711
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
712
+ formatter.print_error(f"Authentication error: {e}")
713
+ raise typer.Exit(1)
714
+ except Exception as e:
715
+ formatter.print_error(f"Failed to get access requirements: {e}")
716
+ raise typer.Exit(1)
717
+
718
+
719
+ @app.command("batch-get-by-path")
720
+ def get_resources_by_path_batch(
721
+ paths: List[str] = typer.Argument(
722
+ ..., help="Absolute paths to resources (space-separated)"
723
+ ),
724
+ profile: Optional[str] = typer.Option(
725
+ None, "--profile", help="Profile name", autocompletion=complete_profile
726
+ ),
727
+ format: str = typer.Option(
728
+ "table",
729
+ "--format",
730
+ "-f",
731
+ help="Output format (table, json, csv)",
732
+ autocompletion=complete_output_format,
733
+ ),
734
+ output: Optional[str] = typer.Option(
735
+ None, "--output", "-o", help="Output file path"
736
+ ),
737
+ ):
738
+ """Get multiple resources by their absolute paths (max 1000)."""
739
+ try:
740
+ if len(paths) > 1000:
741
+ formatter.print_error("Maximum batch size is 1000 paths")
742
+ raise typer.Exit(1)
743
+
744
+ service = ResourceService(profile=profile)
745
+
746
+ with SpinnerProgressTracker().track_spinner(
747
+ f"Fetching {len(paths)} resources by path..."
748
+ ):
749
+ resources = service.get_resources_by_path_batch(paths)
750
+
751
+ # Cache RIDs for future completions
752
+ for resource in resources:
753
+ if resource.get("rid"):
754
+ cache_rid(resource["rid"])
755
+
756
+ # Format output
757
+ if format == "json":
758
+ if output:
759
+ formatter.save_to_file(resources, output, "json")
760
+ else:
761
+ formatter.format_list(resources)
762
+ elif format == "csv":
763
+ if output:
764
+ formatter.save_to_file(resources, output, "csv")
765
+ else:
766
+ formatter.format_list(resources)
767
+ else:
768
+ _format_resources_table(resources)
769
+
770
+ if output:
771
+ formatter.print_success(f"Resources information saved to {output}")
453
772
 
454
773
  except (ProfileNotFoundError, MissingCredentialsError) as e:
455
774
  formatter.print_error(f"Authentication error: {e}")
456
775
  raise typer.Exit(1)
776
+ except ValueError as e:
777
+ formatter.print_error(f"Invalid request: {e}")
778
+ raise typer.Exit(1)
457
779
  except Exception as e:
458
- formatter.print_error(f"Failed to move resource: {e}")
780
+ formatter.print_error(f"Failed to get resources by path batch: {e}")
459
781
  raise typer.Exit(1)
460
782
 
461
783
 
@@ -520,6 +842,70 @@ def _format_metadata_table(metadata: dict):
520
842
  console.print(table)
521
843
 
522
844
 
845
+ def _format_markings_table(markings: List[dict]):
846
+ """Format markings as a table."""
847
+ table = Table(title="Markings", show_header=True, header_style="bold cyan")
848
+ table.add_column("Marking ID")
849
+ table.add_column("Display Name")
850
+ table.add_column("Category")
851
+ table.add_column("Description")
852
+
853
+ for marking in markings:
854
+ table.add_row(
855
+ marking.get("marking_id", "N/A"),
856
+ marking.get("display_name", "N/A"),
857
+ marking.get("category_display_name", "N/A"),
858
+ marking.get("description", "N/A"),
859
+ )
860
+
861
+ console.print(table)
862
+ console.print(f"\nTotal: {len(markings)} markings")
863
+
864
+
865
+ def _format_access_requirements_table(requirements: dict):
866
+ """Format access requirements as tables."""
867
+ organizations = requirements.get("organizations", [])
868
+ markings = requirements.get("markings", [])
869
+
870
+ if organizations:
871
+ org_table = Table(
872
+ title="Required Organizations", show_header=True, header_style="bold cyan"
873
+ )
874
+ org_table.add_column("Organization RID")
875
+ org_table.add_column("Display Name")
876
+
877
+ for org in organizations:
878
+ org_table.add_row(
879
+ org.get("organization_rid", "N/A"),
880
+ org.get("display_name", "N/A"),
881
+ )
882
+
883
+ console.print(org_table)
884
+ console.print(f"Total: {len(organizations)} organizations\n")
885
+ else:
886
+ console.print("[dim]No organization requirements[/dim]\n")
887
+
888
+ if markings:
889
+ marking_table = Table(
890
+ title="Required Markings", show_header=True, header_style="bold cyan"
891
+ )
892
+ marking_table.add_column("Marking ID")
893
+ marking_table.add_column("Display Name")
894
+ marking_table.add_column("Category")
895
+
896
+ for marking in markings:
897
+ marking_table.add_row(
898
+ marking.get("marking_id", "N/A"),
899
+ marking.get("display_name", "N/A"),
900
+ marking.get("category_display_name", "N/A"),
901
+ )
902
+
903
+ console.print(marking_table)
904
+ console.print(f"Total: {len(markings)} markings")
905
+ else:
906
+ console.print("[dim]No marking requirements[/dim]")
907
+
908
+
523
909
  @app.callback()
524
910
  def main():
525
911
  """
@@ -554,7 +940,20 @@ def main():
554
940
  # Get resource metadata
555
941
  pltr resource get-metadata ri.compass.main.dataset.xyz123
556
942
 
557
- # Move resource to different folder
558
- pltr resource move ri.compass.main.dataset.xyz123 --target-folder ri.compass.main.folder.new456
943
+ # Trash operations
944
+ pltr resource delete ri.compass.main.dataset.xyz123
945
+ pltr resource restore ri.compass.main.dataset.xyz123
946
+ pltr resource permanently-delete ri.compass.main.dataset.xyz123
947
+
948
+ # Markings operations
949
+ pltr resource add-markings ri.compass.main.dataset.xyz123 -m marking-id-1 -m marking-id-2
950
+ pltr resource remove-markings ri.compass.main.dataset.xyz123 -m marking-id-1
951
+ pltr resource list-markings ri.compass.main.dataset.xyz123
952
+
953
+ # Access requirements
954
+ pltr resource access-requirements ri.compass.main.dataset.xyz123
955
+
956
+ # Batch get by path
957
+ pltr resource batch-get-by-path "/Org/Project/Dataset1" "/Org/Project/Dataset2"
559
958
  """
560
959
  pass