pltr-cli 0.2.0__py3-none-any.whl → 0.4.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 CHANGED
@@ -23,6 +23,9 @@ if "_PLTR_COMPLETE" in os.environ:
23
23
 
24
24
  # Normal CLI execution
25
25
  from pltr.cli import app
26
+ from pltr.utils.alias_resolver import inject_alias_resolution
26
27
 
27
28
  if __name__ == "__main__":
29
+ # Resolve aliases before running the app
30
+ inject_alias_resolution()
28
31
  app()
pltr/cli.py CHANGED
@@ -10,11 +10,13 @@ from pltr.commands import (
10
10
  configure,
11
11
  verify,
12
12
  dataset,
13
+ folder,
13
14
  ontology,
14
15
  sql,
15
16
  admin,
16
17
  shell,
17
18
  completion,
19
+ alias,
18
20
  )
19
21
 
20
22
  app = typer.Typer(
@@ -27,6 +29,7 @@ app = typer.Typer(
27
29
  app.add_typer(configure.app, name="configure", help="Manage authentication profiles")
28
30
  app.add_typer(verify.app, name="verify", help="Verify authentication")
29
31
  app.add_typer(dataset.app, name="dataset", help="Manage datasets")
32
+ app.add_typer(folder.app, name="folder", help="Manage folders")
30
33
  app.add_typer(ontology.app, name="ontology", help="Ontology operations")
31
34
  app.add_typer(sql.app, name="sql", help="Execute SQL queries")
32
35
  app.add_typer(
@@ -36,6 +39,7 @@ app.add_typer(
36
39
  )
37
40
  app.add_typer(shell.shell_app, name="shell", help="Interactive shell mode")
38
41
  app.add_typer(completion.app, name="completion", help="Manage shell completions")
42
+ app.add_typer(alias.app, name="alias", help="Manage command aliases")
39
43
 
40
44
 
41
45
  def version_callback(value: bool):
pltr/commands/alias.py ADDED
@@ -0,0 +1,241 @@
1
+ """Command alias management commands."""
2
+
3
+ import json
4
+ from typing import Optional
5
+
6
+ import typer
7
+ from rich import print as rprint
8
+
9
+ from pltr.config.aliases import AliasManager
10
+ from pltr.utils.completion import complete_alias_names
11
+
12
+ app = typer.Typer(name="alias", help="Manage command aliases", no_args_is_help=True)
13
+
14
+
15
+ @app.command()
16
+ def add(
17
+ name: str = typer.Argument(..., help="Alias name"),
18
+ command: str = typer.Argument(..., help="Command to alias"),
19
+ force: bool = typer.Option(False, "--force", "-f", help="Overwrite existing alias"),
20
+ ) -> None:
21
+ """Create a new command alias."""
22
+ manager = AliasManager()
23
+
24
+ # Check if alias already exists
25
+ if manager.get_alias(name) and not force:
26
+ rprint(f"[red]Alias '{name}' already exists. Use --force to overwrite.[/red]")
27
+ raise typer.Exit(1)
28
+
29
+ # Check for reserved command names
30
+ reserved_commands = [
31
+ "configure",
32
+ "verify",
33
+ "dataset",
34
+ "ontology",
35
+ "sql",
36
+ "admin",
37
+ "shell",
38
+ "completion",
39
+ "alias",
40
+ "help",
41
+ "--version",
42
+ ]
43
+ if name in reserved_commands:
44
+ rprint(f"[red]Cannot use reserved command name '{name}' as alias[/red]")
45
+ raise typer.Exit(1)
46
+
47
+ try:
48
+ if force and manager.get_alias(name):
49
+ success = manager.edit_alias(name, command)
50
+ action = "Updated"
51
+ else:
52
+ success = manager.add_alias(name, command)
53
+ action = "Created"
54
+
55
+ if success:
56
+ rprint(f"[green]{action} alias:[/green] {name} → {command}")
57
+ else:
58
+ rprint(f"[red]Failed to create alias '{name}'[/red]")
59
+ raise typer.Exit(1)
60
+ except ValueError as e:
61
+ rprint(f"[red]Error: {e}[/red]")
62
+ raise typer.Exit(1)
63
+
64
+
65
+ @app.command()
66
+ def remove(
67
+ name: str = typer.Argument(
68
+ ..., help="Alias name to remove", autocompletion=complete_alias_names
69
+ ),
70
+ confirm: bool = typer.Option(
71
+ True, "--confirm/--no-confirm", help="Confirm removal"
72
+ ),
73
+ ) -> None:
74
+ """Remove a command alias."""
75
+ manager = AliasManager()
76
+
77
+ command = manager.get_alias(name)
78
+ if not command:
79
+ rprint(f"[red]Alias '{name}' not found[/red]")
80
+ raise typer.Exit(1)
81
+
82
+ if confirm:
83
+ confirmation = typer.confirm(f"Remove alias '{name}' → {command}?")
84
+ if not confirmation:
85
+ rprint("[yellow]Removal cancelled[/yellow]")
86
+ return
87
+
88
+ if manager.remove_alias(name):
89
+ rprint(f"[green]Removed alias '{name}'[/green]")
90
+ else:
91
+ rprint(f"[red]Failed to remove alias '{name}'[/red]")
92
+ raise typer.Exit(1)
93
+
94
+
95
+ @app.command()
96
+ def edit(
97
+ name: str = typer.Argument(
98
+ ..., help="Alias name to edit", autocompletion=complete_alias_names
99
+ ),
100
+ command: str = typer.Argument(..., help="New command for the alias"),
101
+ ) -> None:
102
+ """Edit an existing command alias."""
103
+ manager = AliasManager()
104
+
105
+ if not manager.get_alias(name):
106
+ rprint(f"[red]Alias '{name}' not found[/red]")
107
+ raise typer.Exit(1)
108
+
109
+ try:
110
+ if manager.edit_alias(name, command):
111
+ rprint(f"[green]Updated alias:[/green] {name} → {command}")
112
+ else:
113
+ rprint(f"[red]Failed to edit alias '{name}'[/red]")
114
+ raise typer.Exit(1)
115
+ except ValueError as e:
116
+ rprint(f"[red]Error: {e}[/red]")
117
+ raise typer.Exit(1)
118
+
119
+
120
+ @app.command("list")
121
+ def list_aliases() -> None:
122
+ """List all command aliases."""
123
+ manager = AliasManager()
124
+ manager.display_aliases()
125
+
126
+
127
+ @app.command()
128
+ def show(
129
+ name: str = typer.Argument(
130
+ ..., help="Alias name to show", autocompletion=complete_alias_names
131
+ ),
132
+ ) -> None:
133
+ """Show details of a specific alias."""
134
+ manager = AliasManager()
135
+ manager.display_aliases(name)
136
+
137
+
138
+ @app.command()
139
+ def clear(
140
+ confirm: bool = typer.Option(
141
+ True, "--confirm/--no-confirm", help="Confirm clearing all aliases"
142
+ ),
143
+ ) -> None:
144
+ """Clear all command aliases."""
145
+ manager = AliasManager()
146
+
147
+ aliases = manager.list_aliases()
148
+ if not aliases:
149
+ rprint("[yellow]No aliases to clear[/yellow]")
150
+ return
151
+
152
+ if confirm:
153
+ confirmation = typer.confirm(f"Clear all {len(aliases)} aliases?")
154
+ if not confirmation:
155
+ rprint("[yellow]Clear cancelled[/yellow]")
156
+ return
157
+
158
+ count = manager.clear_all()
159
+ rprint(f"[green]Cleared {count} aliases[/green]")
160
+
161
+
162
+ @app.command("export")
163
+ def export_aliases(
164
+ output: Optional[str] = typer.Option(
165
+ None, "--output", "-o", help="Output file (default: stdout)"
166
+ ),
167
+ ) -> None:
168
+ """Export aliases to JSON format."""
169
+ manager = AliasManager()
170
+ aliases = manager.export_aliases()
171
+
172
+ if not aliases:
173
+ rprint("[yellow]No aliases to export[/yellow]")
174
+ return
175
+
176
+ json_data = json.dumps(aliases, indent=2, sort_keys=True)
177
+
178
+ if output:
179
+ with open(output, "w") as f:
180
+ f.write(json_data)
181
+ rprint(f"[green]Exported {len(aliases)} aliases to {output}[/green]")
182
+ else:
183
+ print(json_data)
184
+
185
+
186
+ @app.command("import")
187
+ def import_aliases(
188
+ input_file: str = typer.Argument(..., help="JSON file containing aliases"),
189
+ merge: bool = typer.Option(
190
+ False, "--merge", "-m", help="Merge with existing aliases (default: replace)"
191
+ ),
192
+ ) -> None:
193
+ """Import aliases from a JSON file."""
194
+ manager = AliasManager()
195
+
196
+ try:
197
+ with open(input_file, "r") as f:
198
+ data = json.load(f)
199
+ except (json.JSONDecodeError, IOError) as e:
200
+ rprint(f"[red]Error reading file: {e}[/red]")
201
+ raise typer.Exit(1)
202
+
203
+ if not isinstance(data, dict):
204
+ rprint("[red]Invalid format: expected JSON object with alias mappings[/red]")
205
+ raise typer.Exit(1)
206
+
207
+ # Clear existing aliases if not merging
208
+ if not merge and manager.list_aliases():
209
+ confirmation = typer.confirm("Replace existing aliases?")
210
+ if not confirmation:
211
+ rprint("[yellow]Import cancelled[/yellow]")
212
+ return
213
+ manager.clear_all()
214
+
215
+ count = manager.import_aliases(data)
216
+ rprint(f"[green]Imported {count} aliases from {input_file}[/green]")
217
+
218
+
219
+ @app.command()
220
+ def resolve(
221
+ command: str = typer.Argument(
222
+ ..., help="Command to resolve", autocompletion=complete_alias_names
223
+ ),
224
+ ) -> None:
225
+ """Resolve an alias to show the actual command."""
226
+ manager = AliasManager()
227
+
228
+ resolved = manager.resolve_alias(command)
229
+ if resolved == command:
230
+ if command in manager.list_aliases():
231
+ rprint(
232
+ f"[yellow]'{command}' is an alias but may have circular references[/yellow]"
233
+ )
234
+ else:
235
+ rprint(f"[yellow]'{command}' is not an alias[/yellow]")
236
+ else:
237
+ rprint(f"[green]{command}[/green] → {resolved}")
238
+
239
+
240
+ if __name__ == "__main__":
241
+ app()
@@ -0,0 +1,338 @@
1
+ """
2
+ Folder 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.folder import FolderService
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_folder(
28
+ name: str = typer.Argument(..., help="Folder display name"),
29
+ parent_folder: str = typer.Option(
30
+ "ri.compass.main.folder.0",
31
+ "--parent-folder",
32
+ "-p",
33
+ help="Parent folder RID (default: root folder)",
34
+ autocompletion=complete_rid,
35
+ ),
36
+ profile: Optional[str] = typer.Option(
37
+ None, "--profile", help="Profile name", autocompletion=complete_profile
38
+ ),
39
+ format: str = typer.Option(
40
+ "table",
41
+ "--format",
42
+ "-f",
43
+ help="Output format (table, json, csv)",
44
+ autocompletion=complete_output_format,
45
+ ),
46
+ ):
47
+ """Create a new folder in Foundry."""
48
+ try:
49
+ service = FolderService(profile=profile)
50
+
51
+ with SpinnerProgressTracker().track_spinner(f"Creating folder '{name}'..."):
52
+ folder = service.create_folder(
53
+ display_name=name, parent_folder_rid=parent_folder
54
+ )
55
+
56
+ # Cache the RID for future completions
57
+ if folder.get("rid"):
58
+ cache_rid(folder["rid"])
59
+
60
+ formatter.print_success(f"Successfully created folder '{name}'")
61
+ formatter.print_info(f"Folder RID: {folder.get('rid', 'unknown')}")
62
+
63
+ # Format output
64
+ if format == "json":
65
+ formatter.format_dict(folder)
66
+ elif format == "csv":
67
+ formatter.format_list([folder])
68
+ else:
69
+ _format_folder_table(folder)
70
+
71
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
72
+ formatter.print_error(f"Authentication error: {e}")
73
+ raise typer.Exit(1)
74
+ except Exception as e:
75
+ formatter.print_error(f"Failed to create folder: {e}")
76
+ raise typer.Exit(1)
77
+
78
+
79
+ @app.command("get")
80
+ def get_folder(
81
+ folder_rid: str = typer.Argument(
82
+ ..., help="Folder Resource Identifier", autocompletion=complete_rid
83
+ ),
84
+ profile: Optional[str] = typer.Option(
85
+ None, "--profile", help="Profile name", autocompletion=complete_profile
86
+ ),
87
+ format: str = typer.Option(
88
+ "table",
89
+ "--format",
90
+ "-f",
91
+ help="Output format (table, json, csv)",
92
+ autocompletion=complete_output_format,
93
+ ),
94
+ output: Optional[str] = typer.Option(
95
+ None, "--output", "-o", help="Output file path"
96
+ ),
97
+ ):
98
+ """Get detailed information about a specific folder."""
99
+ try:
100
+ # Cache the RID for future completions
101
+ cache_rid(folder_rid)
102
+
103
+ service = FolderService(profile=profile)
104
+
105
+ with SpinnerProgressTracker().track_spinner(f"Fetching folder {folder_rid}..."):
106
+ folder = service.get_folder(folder_rid)
107
+
108
+ # Format output
109
+ if format == "json":
110
+ if output:
111
+ formatter.save_to_file(folder, output, "json")
112
+ else:
113
+ formatter.format_dict(folder)
114
+ elif format == "csv":
115
+ if output:
116
+ formatter.save_to_file([folder], output, "csv")
117
+ else:
118
+ formatter.format_list([folder])
119
+ else:
120
+ _format_folder_table(folder)
121
+
122
+ if output:
123
+ formatter.print_success(f"Folder information saved to {output}")
124
+
125
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
126
+ formatter.print_error(f"Authentication error: {e}")
127
+ raise typer.Exit(1)
128
+ except Exception as e:
129
+ formatter.print_error(f"Failed to get folder: {e}")
130
+ raise typer.Exit(1)
131
+
132
+
133
+ @app.command("list")
134
+ def list_children(
135
+ folder_rid: str = typer.Argument(
136
+ ...,
137
+ help="Folder Resource Identifier (use 'ri.compass.main.folder.0' for root)",
138
+ autocompletion=complete_rid,
139
+ ),
140
+ profile: Optional[str] = typer.Option(
141
+ None, "--profile", help="Profile name", autocompletion=complete_profile
142
+ ),
143
+ format: str = typer.Option(
144
+ "table",
145
+ "--format",
146
+ "-f",
147
+ help="Output format (table, json, csv)",
148
+ autocompletion=complete_output_format,
149
+ ),
150
+ output: Optional[str] = typer.Option(
151
+ None, "--output", "-o", help="Output file path"
152
+ ),
153
+ page_size: Optional[int] = typer.Option(
154
+ None, "--page-size", help="Number of items per page"
155
+ ),
156
+ ):
157
+ """List all child resources of a folder."""
158
+ try:
159
+ # Cache the RID for future completions
160
+ cache_rid(folder_rid)
161
+
162
+ service = FolderService(profile=profile)
163
+
164
+ with SpinnerProgressTracker().track_spinner(
165
+ f"Listing children of folder {folder_rid}..."
166
+ ):
167
+ children = service.list_children(folder_rid, page_size=page_size)
168
+
169
+ if not children:
170
+ formatter.print_info("No children found in this folder.")
171
+ return
172
+
173
+ # Format output
174
+ if format == "json":
175
+ if output:
176
+ formatter.save_to_file(children, output, "json")
177
+ else:
178
+ formatter.format_list(children)
179
+ elif format == "csv":
180
+ if output:
181
+ formatter.save_to_file(children, output, "csv")
182
+ else:
183
+ formatter.format_list(children)
184
+ else:
185
+ _format_children_table(children)
186
+
187
+ if output:
188
+ formatter.print_success(f"Folder children saved to {output}")
189
+
190
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
191
+ formatter.print_error(f"Authentication error: {e}")
192
+ raise typer.Exit(1)
193
+ except Exception as e:
194
+ formatter.print_error(f"Failed to list folder children: {e}")
195
+ raise typer.Exit(1)
196
+
197
+
198
+ @app.command("batch-get")
199
+ def get_folders_batch(
200
+ folder_rids: List[str] = typer.Argument(
201
+ ..., help="Folder Resource Identifiers (space-separated)"
202
+ ),
203
+ profile: Optional[str] = typer.Option(
204
+ None, "--profile", help="Profile name", autocompletion=complete_profile
205
+ ),
206
+ format: str = typer.Option(
207
+ "table",
208
+ "--format",
209
+ "-f",
210
+ help="Output format (table, json, csv)",
211
+ autocompletion=complete_output_format,
212
+ ),
213
+ output: Optional[str] = typer.Option(
214
+ None, "--output", "-o", help="Output file path"
215
+ ),
216
+ ):
217
+ """Get multiple folders in a single request (max 1000)."""
218
+ try:
219
+ service = FolderService(profile=profile)
220
+
221
+ with SpinnerProgressTracker().track_spinner(
222
+ f"Fetching {len(folder_rids)} folders..."
223
+ ):
224
+ folders = service.get_folders_batch(folder_rids)
225
+
226
+ # Cache RIDs for future completions
227
+ for folder in folders:
228
+ if folder.get("rid"):
229
+ cache_rid(folder["rid"])
230
+
231
+ # Format output
232
+ if format == "json":
233
+ if output:
234
+ formatter.save_to_file(folders, output, "json")
235
+ else:
236
+ formatter.format_list(folders)
237
+ elif format == "csv":
238
+ if output:
239
+ formatter.save_to_file(folders, output, "csv")
240
+ else:
241
+ formatter.format_list(folders)
242
+ else:
243
+ _format_folders_batch_table(folders)
244
+
245
+ if output:
246
+ formatter.print_success(f"Folders information saved to {output}")
247
+
248
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
249
+ formatter.print_error(f"Authentication error: {e}")
250
+ raise typer.Exit(1)
251
+ except ValueError as e:
252
+ formatter.print_error(f"Invalid request: {e}")
253
+ raise typer.Exit(1)
254
+ except Exception as e:
255
+ formatter.print_error(f"Failed to get folders batch: {e}")
256
+ raise typer.Exit(1)
257
+
258
+
259
+ def _format_folder_table(folder: dict):
260
+ """Format folder information as a table."""
261
+ table = Table(
262
+ title="Folder Information", show_header=True, header_style="bold cyan"
263
+ )
264
+ table.add_column("Property", style="cyan")
265
+ table.add_column("Value")
266
+
267
+ table.add_row("RID", folder.get("rid", "N/A"))
268
+ table.add_row("Display Name", folder.get("display_name", "N/A"))
269
+ table.add_row("Description", folder.get("description", "N/A"))
270
+ table.add_row("Parent Folder", folder.get("parent_folder_rid", "N/A"))
271
+ table.add_row("Created", folder.get("created", "N/A"))
272
+ table.add_row("Modified", folder.get("modified", "N/A"))
273
+
274
+ console.print(table)
275
+
276
+
277
+ def _format_children_table(children: List[dict]):
278
+ """Format folder children as a table."""
279
+ table = Table(title="Folder Children", show_header=True, header_style="bold cyan")
280
+ table.add_column("Type", style="cyan")
281
+ table.add_column("Display Name")
282
+ table.add_column("RID")
283
+
284
+ for child in children:
285
+ table.add_row(
286
+ child.get("type", "unknown"),
287
+ child.get("display_name", child.get("name", "N/A")),
288
+ child.get("rid", "N/A"),
289
+ )
290
+
291
+ console.print(table)
292
+ console.print(f"\nTotal: {len(children)} items")
293
+
294
+
295
+ def _format_folders_batch_table(folders: List[dict]):
296
+ """Format multiple folders as a table."""
297
+ table = Table(title="Folders", show_header=True, header_style="bold cyan")
298
+ table.add_column("Display Name")
299
+ table.add_column("RID")
300
+ table.add_column("Parent Folder")
301
+ table.add_column("Description")
302
+
303
+ for folder in folders:
304
+ table.add_row(
305
+ folder.get("display_name", "N/A"),
306
+ folder.get("rid", "N/A"),
307
+ folder.get("parent_folder_rid", "N/A"),
308
+ folder.get("description", "N/A") or "",
309
+ )
310
+
311
+ console.print(table)
312
+ console.print(f"\nTotal: {len(folders)} folders")
313
+
314
+
315
+ @app.callback()
316
+ def main():
317
+ """
318
+ Folder operations using foundry-platform-sdk.
319
+
320
+ Manage folders in the Foundry filesystem. Create, retrieve, and list
321
+ folder contents using Resource Identifiers (RIDs).
322
+
323
+ The root folder RID is: ri.compass.main.folder.0
324
+
325
+ Examples:
326
+ # Create a folder in root
327
+ pltr folder create "My Folder"
328
+
329
+ # Create a folder in a specific parent
330
+ pltr folder create "Sub Folder" --parent-folder ri.compass.main.folder.xyz123
331
+
332
+ # List root folder contents
333
+ pltr folder list ri.compass.main.folder.0
334
+
335
+ # Get folder information
336
+ pltr folder get ri.compass.main.folder.xyz123
337
+ """
338
+ pass
pltr/commands/ontology.py CHANGED
@@ -33,16 +33,13 @@ def list_ontologies(
33
33
  output: Optional[str] = typer.Option(
34
34
  None, "--output", "-o", help="Output file path"
35
35
  ),
36
- page_size: Optional[int] = typer.Option(
37
- None, "--page-size", help="Number of results per page"
38
- ),
39
36
  ):
40
37
  """List all available ontologies."""
41
38
  try:
42
39
  service = OntologyService(profile=profile)
43
40
 
44
41
  with SpinnerProgressTracker().track_spinner("Fetching ontologies..."):
45
- ontologies = service.list_ontologies(page_size=page_size)
42
+ ontologies = service.list_ontologies()
46
43
 
47
44
  formatter.format_table(
48
45
  ontologies,
@@ -106,16 +103,13 @@ def list_object_types(
106
103
  output: Optional[str] = typer.Option(
107
104
  None, "--output", "-o", help="Output file path"
108
105
  ),
109
- page_size: Optional[int] = typer.Option(
110
- None, "--page-size", help="Number of results per page"
111
- ),
112
106
  ):
113
107
  """List object types in an ontology."""
114
108
  try:
115
109
  service = ObjectTypeService(profile=profile)
116
110
 
117
111
  with SpinnerProgressTracker().track_spinner("Fetching object types..."):
118
- object_types = service.list_object_types(ontology_rid, page_size=page_size)
112
+ object_types = service.list_object_types(ontology_rid)
119
113
 
120
114
  formatter.format_table(
121
115
  object_types,
pltr/config/aliases.py ADDED
@@ -0,0 +1,254 @@
1
+ """Alias configuration management for pltr-cli."""
2
+
3
+ import json
4
+ from typing import Dict, List, Optional
5
+
6
+ from rich import print as rprint
7
+ from rich.table import Table
8
+
9
+ from pltr.config.settings import Settings
10
+
11
+
12
+ class AliasManager:
13
+ """Manages command aliases for pltr-cli."""
14
+
15
+ def __init__(self) -> None:
16
+ """Initialize the alias manager."""
17
+ settings = Settings()
18
+ self.config_dir = settings.config_dir
19
+ self.aliases_file = self.config_dir / "aliases.json"
20
+ self.aliases = self._load_aliases()
21
+
22
+ def _load_aliases(self) -> Dict[str, str]:
23
+ """Load aliases from the configuration file.
24
+
25
+ Returns:
26
+ Dictionary mapping alias names to commands
27
+ """
28
+ if not self.aliases_file.exists():
29
+ return {}
30
+
31
+ try:
32
+ with open(self.aliases_file, "r") as f:
33
+ return json.load(f)
34
+ except (json.JSONDecodeError, IOError):
35
+ return {}
36
+
37
+ def _save_aliases(self) -> None:
38
+ """Save aliases to the configuration file."""
39
+ self.config_dir.mkdir(parents=True, exist_ok=True)
40
+ with open(self.aliases_file, "w") as f:
41
+ json.dump(self.aliases, f, indent=2, sort_keys=True)
42
+
43
+ def add_alias(self, name: str, command: str) -> bool:
44
+ """Add a new alias.
45
+
46
+ Args:
47
+ name: Alias name
48
+ command: Command to alias
49
+
50
+ Returns:
51
+ True if alias was added, False if it already exists
52
+
53
+ Raises:
54
+ ValueError: If the alias would create a circular reference
55
+ """
56
+ if name in self.aliases:
57
+ return False
58
+
59
+ # Check for circular references
60
+ if self._would_create_cycle(name, command):
61
+ raise ValueError(f"Alias '{name}' would create a circular reference")
62
+
63
+ self.aliases[name] = command
64
+ self._save_aliases()
65
+ return True
66
+
67
+ def remove_alias(self, name: str) -> bool:
68
+ """Remove an alias.
69
+
70
+ Args:
71
+ name: Alias name to remove
72
+
73
+ Returns:
74
+ True if alias was removed, False if it didn't exist
75
+ """
76
+ if name not in self.aliases:
77
+ return False
78
+
79
+ del self.aliases[name]
80
+ self._save_aliases()
81
+ return True
82
+
83
+ def edit_alias(self, name: str, command: str) -> bool:
84
+ """Edit an existing alias.
85
+
86
+ Args:
87
+ name: Alias name to edit
88
+ command: New command for the alias
89
+
90
+ Returns:
91
+ True if alias was edited, False if it doesn't exist
92
+ """
93
+ if name not in self.aliases:
94
+ return False
95
+
96
+ # Check for circular references
97
+ if self._would_create_cycle(name, command):
98
+ raise ValueError(f"Alias '{name}' would create a circular reference")
99
+
100
+ self.aliases[name] = command
101
+ self._save_aliases()
102
+ return True
103
+
104
+ def get_alias(self, name: str) -> Optional[str]:
105
+ """Get the command for an alias.
106
+
107
+ Args:
108
+ name: Alias name
109
+
110
+ Returns:
111
+ The aliased command, or None if alias doesn't exist
112
+ """
113
+ return self.aliases.get(name)
114
+
115
+ def list_aliases(self) -> Dict[str, str]:
116
+ """Get all aliases.
117
+
118
+ Returns:
119
+ Dictionary of all aliases
120
+ """
121
+ return self.aliases.copy()
122
+
123
+ def resolve_alias(self, command: str, max_depth: int = 10) -> str:
124
+ """Resolve an alias to its final command.
125
+
126
+ Args:
127
+ command: Command that might be an alias
128
+ max_depth: Maximum recursion depth for nested aliases
129
+
130
+ Returns:
131
+ The resolved command
132
+ """
133
+ resolved = command
134
+ depth = 0
135
+ seen = set()
136
+
137
+ while resolved in self.aliases and depth < max_depth:
138
+ if resolved in seen:
139
+ # Circular reference detected
140
+ return command
141
+
142
+ seen.add(resolved)
143
+ resolved = self.aliases[resolved]
144
+ depth += 1
145
+
146
+ return resolved
147
+
148
+ def _would_create_cycle(self, name: str, command: str) -> bool:
149
+ """Check if adding/editing an alias would create a cycle.
150
+
151
+ Args:
152
+ name: Alias name
153
+ command: Command to check
154
+
155
+ Returns:
156
+ True if this would create a cycle
157
+ """
158
+ # Direct self-reference
159
+ if command == name:
160
+ return True
161
+
162
+ # Follow the chain starting from command
163
+ # If we ever reach 'name', it would create a cycle
164
+ current = command
165
+ visited = set()
166
+
167
+ while current in self.aliases:
168
+ # Check for existing cycles
169
+ if current in visited:
170
+ break
171
+ visited.add(current)
172
+
173
+ # Get what this alias points to
174
+ current = self.aliases[current]
175
+
176
+ # If we reached the name we're trying to add, it's a cycle
177
+ if current == name:
178
+ return True
179
+
180
+ return False
181
+
182
+ def display_aliases(self, name: Optional[str] = None) -> None:
183
+ """Display aliases in a formatted table.
184
+
185
+ Args:
186
+ name: Optional specific alias to display
187
+ """
188
+ if name:
189
+ command = self.get_alias(name)
190
+ if command:
191
+ rprint(f"[green]{name}[/green] → {command}")
192
+ else:
193
+ rprint(f"[red]Alias '{name}' not found[/red]")
194
+ return
195
+
196
+ if not self.aliases:
197
+ rprint("[yellow]No aliases configured[/yellow]")
198
+ return
199
+
200
+ table = Table(title="Command Aliases", show_header=True)
201
+ table.add_column("Alias", style="cyan")
202
+ table.add_column("Command", style="green")
203
+
204
+ for alias_name, command in sorted(self.aliases.items()):
205
+ table.add_row(alias_name, command)
206
+
207
+ rprint(table)
208
+
209
+ def get_completion_items(self) -> List[str]:
210
+ """Get alias names for shell completion.
211
+
212
+ Returns:
213
+ List of alias names
214
+ """
215
+ return list(self.aliases.keys())
216
+
217
+ def clear_all(self) -> int:
218
+ """Clear all aliases.
219
+
220
+ Returns:
221
+ Number of aliases cleared
222
+ """
223
+ count = len(self.aliases)
224
+ self.aliases = {}
225
+ self._save_aliases()
226
+ return count
227
+
228
+ def import_aliases(self, data: Dict[str, str]) -> int:
229
+ """Import aliases from a dictionary.
230
+
231
+ Args:
232
+ data: Dictionary of aliases to import
233
+
234
+ Returns:
235
+ Number of aliases imported
236
+ """
237
+ count = 0
238
+ for name, command in data.items():
239
+ if not self._would_create_cycle(name, command):
240
+ self.aliases[name] = command
241
+ count += 1
242
+
243
+ if count > 0:
244
+ self._save_aliases()
245
+
246
+ return count
247
+
248
+ def export_aliases(self) -> Dict[str, str]:
249
+ """Export all aliases.
250
+
251
+ Returns:
252
+ Dictionary of all aliases
253
+ """
254
+ return self.aliases.copy()
@@ -0,0 +1,167 @@
1
+ """
2
+ Folder service wrapper for Foundry SDK filesystem API.
3
+ """
4
+
5
+ from typing import Any, Optional, Dict, List
6
+
7
+ from .base import BaseService
8
+
9
+
10
+ class FolderService(BaseService):
11
+ """Service wrapper for Foundry folder operations using filesystem API."""
12
+
13
+ def _get_service(self) -> Any:
14
+ """Get the Foundry filesystem service."""
15
+ return self.client.filesystem
16
+
17
+ def create_folder(
18
+ self, display_name: str, parent_folder_rid: str
19
+ ) -> Dict[str, Any]:
20
+ """
21
+ Create a new folder.
22
+
23
+ Args:
24
+ display_name: Folder display name
25
+ parent_folder_rid: Parent folder RID (use 'ri.compass.main.folder.0' for root)
26
+
27
+ Returns:
28
+ Created folder information
29
+ """
30
+ try:
31
+ folder = self.service.Folder.create(
32
+ display_name=display_name,
33
+ parent_folder_rid=parent_folder_rid,
34
+ preview=True,
35
+ )
36
+ return self._format_folder_info(folder)
37
+ except Exception as e:
38
+ raise RuntimeError(f"Failed to create folder '{display_name}': {e}")
39
+
40
+ def get_folder(self, folder_rid: str) -> Dict[str, Any]:
41
+ """
42
+ Get information about a specific folder.
43
+
44
+ Args:
45
+ folder_rid: Folder Resource Identifier
46
+
47
+ Returns:
48
+ Folder information dictionary
49
+ """
50
+ try:
51
+ folder = self.service.Folder.get(folder_rid, preview=True)
52
+ return self._format_folder_info(folder)
53
+ except Exception as e:
54
+ raise RuntimeError(f"Failed to get folder {folder_rid}: {e}")
55
+
56
+ def list_children(
57
+ self,
58
+ folder_rid: str,
59
+ page_size: Optional[int] = None,
60
+ page_token: Optional[str] = None,
61
+ ) -> List[Dict[str, Any]]:
62
+ """
63
+ List all child resources of a folder.
64
+
65
+ Args:
66
+ folder_rid: Folder Resource Identifier
67
+ page_size: Number of items per page (optional)
68
+ page_token: Pagination token (optional)
69
+
70
+ Returns:
71
+ List of child resources
72
+ """
73
+ try:
74
+ children = []
75
+ # The children method returns an iterator
76
+ for child in self.service.Folder.children(
77
+ folder_rid, page_size=page_size, page_token=page_token, preview=True
78
+ ):
79
+ children.append(self._format_resource_info(child))
80
+ return children
81
+ except Exception as e:
82
+ raise RuntimeError(f"Failed to list children of folder {folder_rid}: {e}")
83
+
84
+ def get_folders_batch(self, folder_rids: List[str]) -> List[Dict[str, Any]]:
85
+ """
86
+ Get multiple folders in a single request.
87
+
88
+ Args:
89
+ folder_rids: List of folder RIDs (max 1000)
90
+
91
+ Returns:
92
+ List of folder information dictionaries
93
+ """
94
+ if len(folder_rids) > 1000:
95
+ raise ValueError("Maximum batch size is 1000 folders")
96
+
97
+ try:
98
+ response = self.service.Folder.get_batch(body=folder_rids, preview=True)
99
+ folders = []
100
+ for folder in response.folders:
101
+ folders.append(self._format_folder_info(folder))
102
+ return folders
103
+ except Exception as e:
104
+ raise RuntimeError(f"Failed to get folders batch: {e}")
105
+
106
+ def _format_folder_info(self, folder: Any) -> Dict[str, Any]:
107
+ """
108
+ Format folder information for consistent output.
109
+
110
+ Args:
111
+ folder: Folder object from Foundry SDK
112
+
113
+ Returns:
114
+ Formatted folder information dictionary
115
+ """
116
+ return {
117
+ "rid": getattr(folder, "rid", None),
118
+ "display_name": getattr(folder, "display_name", None),
119
+ "description": getattr(folder, "description", None),
120
+ "created": self._format_timestamp(getattr(folder, "created", None)),
121
+ "modified": self._format_timestamp(getattr(folder, "modified", None)),
122
+ "parent_folder_rid": getattr(folder, "parent_folder_rid", None),
123
+ "type": "folder",
124
+ }
125
+
126
+ def _format_resource_info(self, resource: Any) -> Dict[str, Any]:
127
+ """
128
+ Format resource information (can be folder, dataset, etc.).
129
+
130
+ Args:
131
+ resource: Resource object from Foundry SDK
132
+
133
+ Returns:
134
+ Formatted resource information dictionary
135
+ """
136
+ resource_type = getattr(resource, "type", "unknown")
137
+ base_info = {
138
+ "rid": getattr(resource, "rid", None),
139
+ "display_name": getattr(resource, "display_name", None),
140
+ "type": resource_type,
141
+ }
142
+
143
+ # Add type-specific fields
144
+ if resource_type == "folder":
145
+ base_info["description"] = getattr(resource, "description", None)
146
+ elif resource_type == "dataset":
147
+ base_info["name"] = getattr(resource, "name", None)
148
+
149
+ return base_info
150
+
151
+ def _format_timestamp(self, timestamp: Any) -> Optional[str]:
152
+ """
153
+ Format timestamp for display.
154
+
155
+ Args:
156
+ timestamp: Timestamp object from SDK
157
+
158
+ Returns:
159
+ Formatted timestamp string or None
160
+ """
161
+ if timestamp is None:
162
+ return None
163
+
164
+ # Handle different timestamp formats from the SDK
165
+ if hasattr(timestamp, "time"):
166
+ return str(timestamp.time)
167
+ return str(timestamp)
pltr/services/ontology.py CHANGED
@@ -13,20 +13,18 @@ class OntologyService(BaseService):
13
13
  """Get the Foundry ontologies service."""
14
14
  return self.client.ontologies
15
15
 
16
- def list_ontologies(self, page_size: Optional[int] = None) -> List[Dict[str, Any]]:
16
+ def list_ontologies(self) -> List[Dict[str, Any]]:
17
17
  """
18
18
  List all ontologies visible to the current user.
19
19
 
20
- Args:
21
- page_size: Number of results per page
22
-
23
20
  Returns:
24
21
  List of ontology information dictionaries
25
22
  """
26
23
  try:
27
- result = self.service.Ontology.list(page_size=page_size)
24
+ result = self.service.Ontology.list()
28
25
  ontologies = []
29
- for ontology in result:
26
+ # The response has a 'data' field containing the list of ontologies
27
+ for ontology in result.data:
30
28
  ontologies.append(self._format_ontology_info(ontology))
31
29
  return ontologies
32
30
  except Exception as e:
@@ -65,23 +63,22 @@ class ObjectTypeService(BaseService):
65
63
  """Get the Foundry ontologies service."""
66
64
  return self.client.ontologies
67
65
 
68
- def list_object_types(
69
- self, ontology_rid: str, page_size: Optional[int] = None
70
- ) -> List[Dict[str, Any]]:
66
+ def list_object_types(self, ontology_rid: str) -> List[Dict[str, Any]]:
71
67
  """
72
68
  List object types in an ontology.
73
69
 
74
70
  Args:
75
71
  ontology_rid: Ontology Resource Identifier
76
- page_size: Number of results per page
77
72
 
78
73
  Returns:
79
74
  List of object type information dictionaries
80
75
  """
81
76
  try:
82
- result = self.service.ObjectType.list(ontology_rid, page_size=page_size)
77
+ # ObjectType is nested under Ontology in the SDK
78
+ result = self.service.Ontology.ObjectType.list(ontology_rid)
83
79
  object_types = []
84
- for obj_type in result:
80
+ # The response has a 'data' field containing the list of object types
81
+ for obj_type in result.data:
85
82
  object_types.append(self._format_object_type_info(obj_type))
86
83
  return object_types
87
84
  except Exception as e:
@@ -99,13 +96,14 @@ class ObjectTypeService(BaseService):
99
96
  Object type information dictionary
100
97
  """
101
98
  try:
102
- obj_type = self.service.ObjectType.get(ontology_rid, object_type)
99
+ # ObjectType is nested under Ontology in the SDK
100
+ obj_type = self.service.Ontology.ObjectType.get(ontology_rid, object_type)
103
101
  return self._format_object_type_info(obj_type)
104
102
  except Exception as e:
105
103
  raise RuntimeError(f"Failed to get object type {object_type}: {e}")
106
104
 
107
105
  def list_outgoing_link_types(
108
- self, ontology_rid: str, object_type: str, page_size: Optional[int] = None
106
+ self, ontology_rid: str, object_type: str
109
107
  ) -> List[Dict[str, Any]]:
110
108
  """
111
109
  List outgoing link types for an object type.
@@ -113,17 +111,18 @@ class ObjectTypeService(BaseService):
113
111
  Args:
114
112
  ontology_rid: Ontology Resource Identifier
115
113
  object_type: Object type API name
116
- page_size: Number of results per page
117
114
 
118
115
  Returns:
119
116
  List of link type information dictionaries
120
117
  """
121
118
  try:
122
- result = self.service.ObjectType.list_outgoing_link_types(
123
- ontology_rid, object_type, page_size=page_size
119
+ # ObjectType is nested under Ontology in the SDK
120
+ result = self.service.Ontology.ObjectType.list_outgoing_link_types(
121
+ ontology_rid, object_type
124
122
  )
125
123
  link_types = []
126
- for link_type in result:
124
+ # The response has a 'data' field containing the list of link types
125
+ for link_type in result.data:
127
126
  link_types.append(self._format_link_type_info(link_type))
128
127
  return link_types
129
128
  except Exception as e:
@@ -0,0 +1,56 @@
1
+ """Alias resolution utilities for CLI commands."""
2
+
3
+ import shlex
4
+ import sys
5
+ from typing import List, Optional
6
+
7
+ from pltr.config.aliases import AliasManager
8
+
9
+
10
+ def resolve_command_aliases(args: Optional[List[str]] = None) -> List[str]:
11
+ """Resolve command aliases in the argument list.
12
+
13
+ Args:
14
+ args: Command arguments (defaults to sys.argv[1:])
15
+
16
+ Returns:
17
+ Resolved command arguments
18
+ """
19
+ if args is None:
20
+ args = sys.argv[1:]
21
+
22
+ if not args:
23
+ return args
24
+
25
+ # Don't resolve aliases for certain commands
26
+ if args[0] in ["alias", "--help", "-h", "--version", "completion"]:
27
+ return args
28
+
29
+ # Check if the first argument is an alias
30
+ manager = AliasManager()
31
+ first_arg = args[0]
32
+
33
+ # Try to resolve as an alias
34
+ resolved = manager.resolve_alias(first_arg)
35
+
36
+ if resolved != first_arg:
37
+ # It's an alias - parse the resolved command
38
+ try:
39
+ resolved_parts = shlex.split(resolved)
40
+ # Replace the first argument with the resolved command parts
41
+ # and append any additional arguments
42
+ return resolved_parts + args[1:]
43
+ except ValueError:
44
+ # If parsing fails, return original args
45
+ return args
46
+
47
+ return args
48
+
49
+
50
+ def inject_alias_resolution() -> None:
51
+ """Inject alias resolution into sys.argv before CLI parsing."""
52
+ # Get resolved arguments
53
+ resolved_args = resolve_command_aliases()
54
+
55
+ # Replace sys.argv with resolved arguments
56
+ sys.argv = [sys.argv[0]] + resolved_args
pltr/utils/completion.py CHANGED
@@ -6,6 +6,7 @@ from pathlib import Path
6
6
  import json
7
7
 
8
8
  from pltr.config.profiles import ProfileManager
9
+ from pltr.config.aliases import AliasManager
9
10
 
10
11
 
11
12
  def get_cached_rids() -> List[str]:
@@ -111,6 +112,13 @@ def complete_ontology_action(incomplete: str):
111
112
  return [action for action in actions if action.startswith(incomplete)]
112
113
 
113
114
 
115
+ def complete_alias_names(incomplete: str):
116
+ """Complete alias names."""
117
+ manager = AliasManager()
118
+ aliases = manager.get_completion_items()
119
+ return [alias for alias in aliases if alias.startswith(incomplete)]
120
+
121
+
114
122
  def complete_file_path(incomplete: str):
115
123
  """Complete file paths."""
116
124
  # This is handled by shell natively, but we can provide hints
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pltr-cli
3
- Version: 0.2.0
3
+ Version: 0.4.0
4
4
  Summary: Command-line interface for Palantir Foundry APIs
5
5
  Project-URL: Homepage, https://github.com/anjor/pltr-cli
6
6
  Project-URL: Repository, https://github.com/anjor/pltr-cli
@@ -37,7 +37,7 @@ Description-Content-Type: text/markdown
37
37
 
38
38
  # pltr-cli
39
39
 
40
- A comprehensive command-line interface for Palantir Foundry APIs, providing 65+ commands for data analysis, ontology operations, SQL queries, and administrative tasks.
40
+ A comprehensive command-line interface for Palantir Foundry APIs, providing 70+ commands for data analysis, ontology operations, SQL queries, folder management, and administrative tasks.
41
41
 
42
42
  ## Overview
43
43
 
@@ -47,6 +47,7 @@ A comprehensive command-line interface for Palantir Foundry APIs, providing 65+
47
47
 
48
48
  - 🔐 **Secure Authentication**: Token and OAuth2 support with encrypted credential storage
49
49
  - 📊 **Dataset Operations**: Get dataset information and create new datasets (RID-based API)
50
+ - 📁 **Folder Management**: Create, explore, and manage Foundry filesystem structure
50
51
  - 🎯 **Comprehensive Ontology Access**: 13 commands for objects, actions, and queries
51
52
  - 📝 **Full SQL Support**: Execute, submit, monitor, and export query results
52
53
  - 👥 **Admin Operations**: User, group, role, and organization management (16 commands)
@@ -109,6 +110,12 @@ pltr admin user current
109
110
  # List available ontologies
110
111
  pltr ontology list
111
112
 
113
+ # Create a new folder
114
+ pltr folder create "My Project"
115
+
116
+ # List root folder contents
117
+ pltr folder list ri.compass.main.folder.0
118
+
112
119
  # Execute a simple SQL query
113
120
  pltr sql execute "SELECT 1 as test"
114
121
 
@@ -133,7 +140,7 @@ pltr-cli provides comprehensive documentation to help you get the most out of th
133
140
  ### 📖 User Guides
134
141
  - **[Quick Start Guide](docs/user-guide/quick-start.md)** - Get up and running in 5 minutes
135
142
  - **[Authentication Setup](docs/user-guide/authentication.md)** - Complete guide to token and OAuth2 setup
136
- - **[Command Reference](docs/user-guide/commands.md)** - Complete reference for all 65+ commands
143
+ - **[Command Reference](docs/user-guide/commands.md)** - Complete reference for all 70+ commands
137
144
  - **[Common Workflows](docs/user-guide/workflows.md)** - Real-world data analysis patterns
138
145
  - **[Troubleshooting](docs/user-guide/troubleshooting.md)** - Solutions to common issues
139
146
 
@@ -1,6 +1,6 @@
1
1
  pltr/__init__.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
2
- pltr/__main__.py,sha256=PQIEddxNh3RNfW-pW0DFDgH2r_RptnKvgBcF9N4S5ik,742
3
- pltr/cli.py,sha256=lJU7EMPjHkaehA32CJh3d6zUNF8iEGHqGX-K45ErqhU,1798
2
+ pltr/__main__.py,sha256=HWJ49UoAYBQCf8kjuySPmBTuUjTZrOx-y6PzMTyS1KE,879
3
+ pltr/cli.py,sha256=cogkxi-J2hKrWKzjRFy6GLvcsPfrE_r_pAG6EMmuJ8s,1955
4
4
  pltr/auth/__init__.py,sha256=G0V-Rh25FaJsH2nhrf146XQQG_ApdbyPJNuHJC25kgk,38
5
5
  pltr/auth/base.py,sha256=LvmCwS7A0q0CITcym8udPzdACL52_jSGusiaeCTOaE8,981
6
6
  pltr/auth/manager.py,sha256=ZqlGefr1a8MGx0g7kkQhpmiuVp0XTg3f43yMBCk-IRo,4305
@@ -9,14 +9,17 @@ pltr/auth/storage.py,sha256=C7I3-22CJcnrKGNdxk9nXjphsnqQVguT5gNfAnR78Ok,2474
9
9
  pltr/auth/token.py,sha256=V48kxGn7CFbNGo17er5oI_ZA3xJ3iS9TsFjphZYqS2s,1925
10
10
  pltr/commands/__init__.py,sha256=iOLJ1ql4mz-3-4nz21hAqjd-9IjpYAIxr9SJQKHNFxM,29
11
11
  pltr/commands/admin.py,sha256=foscSO-QuH6uggUR5Rmv9pTqGjEXTUzpmMFj2-8hEJs,17065
12
+ pltr/commands/alias.py,sha256=r9xMsQNrGvaixSlspzoO2IXQ44LFXuZM4itt8vC0dRc,6862
12
13
  pltr/commands/completion.py,sha256=YTxaRL4-rDs5n7aXf3ogFsxbHVJUBo_HiBbd0fbBPZ0,10870
13
14
  pltr/commands/configure.py,sha256=oYj-VlOEj3MDwtB2RC4bYOYzI_sXTanPnz7y1GmMTqY,4800
14
15
  pltr/commands/dataset.py,sha256=BCYfaBpLji5wasOiH_jOqO-JC9ScfJhodox9kl9W2Cw,3609
15
- pltr/commands/ontology.py,sha256=3MwGsRgCzOsG5OTo0xu1iNa3tpZy64e_Fy3O8I45_5I,18587
16
+ pltr/commands/folder.py,sha256=IAPPA3Smk1IWqThneEtZ08Zp79vDKVUabSkL_nDvUWk,10679
17
+ pltr/commands/ontology.py,sha256=zUgSrmv8xi26SQK7GsM3qusgR9Wuka0GyzE7L8DkduE,18317
16
18
  pltr/commands/shell.py,sha256=QLF7TEGpaau9i0A9s3VjnegvtHde-SLRqI4suJFT4WI,3622
17
19
  pltr/commands/sql.py,sha256=wol0Rlvi_RplCFbOg4LCa3VXsOqmRZdFFVv7V6iVkh8,12602
18
20
  pltr/commands/verify.py,sha256=n8LWhbfGieYa-a5_l3MxqkYbdpyVf8-i0FQIL__AaPA,6650
19
21
  pltr/config/__init__.py,sha256=Y6gARy5lUHy-OJaOUxtfXoeQVNZV5QHLl6uKHQ8tpTk,41
22
+ pltr/config/aliases.py,sha256=ZmesZWMfa5riZlVe3fyC7EI3uIzxEGsDHz-8shOpIbM,6947
20
23
  pltr/config/profiles.py,sha256=XMUIp6Ez5LNC6rGXZe2JLH7IKepXhARtuc8ASUA9FYA,3431
21
24
  pltr/config/settings.py,sha256=bfIiosPqH_W73TOHS71DvgZdAHka4fJDopU1SvBRFuQ,2908
22
25
  pltr/services/__init__.py,sha256=zQpgrqPdAkZI-nobi33mctU2-iGNgazzvjBVY8YRbSQ,101
@@ -25,14 +28,16 @@ pltr/services/base.py,sha256=R2G781FI-sXtjUyLd91bVnmLb4cYZI3G8U5ndR9NLA4,1593
25
28
  pltr/services/dataset.py,sha256=W3zoh-9YIJ6HBsDijejVEngKvpudFoZinYtHDmAXCOc,2785
26
29
  pltr/services/dataset_full.py,sha256=FyMiwOSyX1cUrYXaK0T_1iq5G_X0e5iZTibJHuEmMeE,9869
27
30
  pltr/services/dataset_v2.py,sha256=_uhcVJ91w_Y07glceqHceccAwPWr6q1TWSIqcP1FU8I,4259
28
- pltr/services/ontology.py,sha256=d5MD0QeLfqs6W_XdteiK1da0yo_TKSftBmEOfPiLvf8,14755
31
+ pltr/services/folder.py,sha256=mWElyvn-wXPB5sv8Ik_dLeW5JM6jZg3g9KKBk6UcrlQ,5389
32
+ pltr/services/ontology.py,sha256=iW7qRK8ptlw-u4eAwLNC-mdzLoLZzh7SRqJyok2c3GU,14883
29
33
  pltr/services/sql.py,sha256=19cscjlzN8WE1s8_ctiRcrOvMzCfmWRj49vjJ8Gs5Q4,11286
30
34
  pltr/utils/__init__.py,sha256=DF7TigL1XbKVGM5VjgU8_8AGIszofkdO80oCzLGGnTE,38
31
- pltr/utils/completion.py,sha256=QdTkpT9MMs7C7keuJi79sMLerFX3CarpB4FrCKImjSc,4712
35
+ pltr/utils/alias_resolver.py,sha256=DIF7P1UnUU8kqocJfIDEWjYq4s8_0KfqRZBbECeZEh8,1539
36
+ pltr/utils/completion.py,sha256=bjeqjleEfB2YcQFpcxvF0GoQ763F6KBbULSZC4FWY_g,4980
32
37
  pltr/utils/formatting.py,sha256=Ptv7obiB7uWNf5YTiY4rUAKmabO5UGnwLocSfLplrZ0,18552
33
38
  pltr/utils/progress.py,sha256=BKYbiLO61uhQbibabU7pxvvbAWMRLRmqk4pZldBQK_g,9053
34
- pltr_cli-0.2.0.dist-info/METADATA,sha256=xk4xxyxl6TXmvgvrcfkR91E-TgnJiA4FdDY6ElW434Y,8864
35
- pltr_cli-0.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
36
- pltr_cli-0.2.0.dist-info/entry_points.txt,sha256=8tvEcW04kA_oAE2Dwwu-Og9efjl4ESJvs4AzlP2KBdQ,38
37
- pltr_cli-0.2.0.dist-info/licenses/LICENSE,sha256=6VUFd_ytnOBD2O1tmkKrA-smigi9QEhYr_tge4h4z8Y,1070
38
- pltr_cli-0.2.0.dist-info/RECORD,,
39
+ pltr_cli-0.4.0.dist-info/METADATA,sha256=RDHEVijMZLcjzM8fBjaNm8DQsY0PIK8339CbDK64s-s,9096
40
+ pltr_cli-0.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
41
+ pltr_cli-0.4.0.dist-info/entry_points.txt,sha256=8tvEcW04kA_oAE2Dwwu-Og9efjl4ESJvs4AzlP2KBdQ,38
42
+ pltr_cli-0.4.0.dist-info/licenses/LICENSE,sha256=6VUFd_ytnOBD2O1tmkKrA-smigi9QEhYr_tge4h4z8Y,1070
43
+ pltr_cli-0.4.0.dist-info/RECORD,,