pltr-cli 0.11.0__py3-none-any.whl → 0.12.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pltr/__init__.py +1 -1
- pltr/cli.py +16 -0
- pltr/commands/admin.py +553 -9
- pltr/commands/aip_agents.py +333 -0
- pltr/commands/connectivity.py +309 -1
- pltr/commands/cp.py +103 -0
- pltr/commands/dataset.py +104 -4
- pltr/commands/mediasets.py +176 -0
- pltr/commands/ontology.py +44 -13
- pltr/commands/orchestration.py +167 -11
- pltr/commands/project.py +249 -0
- pltr/commands/resource.py +452 -0
- pltr/commands/sql.py +54 -7
- pltr/commands/third_party_applications.py +82 -0
- pltr/services/admin.py +318 -1
- pltr/services/aip_agents.py +147 -0
- pltr/services/base.py +104 -1
- pltr/services/connectivity.py +139 -0
- pltr/services/copy.py +391 -0
- pltr/services/dataset.py +75 -1
- pltr/services/mediasets.py +144 -9
- pltr/services/ontology.py +48 -1
- pltr/services/orchestration.py +133 -1
- pltr/services/project.py +136 -0
- pltr/services/resource.py +227 -0
- pltr/services/sql.py +44 -20
- pltr/services/third_party_applications.py +53 -0
- pltr/utils/formatting.py +195 -1
- pltr/utils/pagination.py +325 -0
- {pltr_cli-0.11.0.dist-info → pltr_cli-0.12.0.dist-info}/METADATA +5 -3
- pltr_cli-0.12.0.dist-info/RECORD +62 -0
- {pltr_cli-0.11.0.dist-info → pltr_cli-0.12.0.dist-info}/WHEEL +1 -1
- pltr_cli-0.11.0.dist-info/RECORD +0 -55
- {pltr_cli-0.11.0.dist-info → pltr_cli-0.12.0.dist-info}/entry_points.txt +0 -0
- {pltr_cli-0.11.0.dist-info → pltr_cli-0.12.0.dist-info}/licenses/LICENSE +0 -0
pltr/services/dataset.py
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
Dataset service wrapper for Foundry SDK.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from typing import Any,
|
|
5
|
+
from typing import Any, Callable, Dict, List, Optional, Union
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
import csv
|
|
8
8
|
|
|
9
|
+
from ..config.settings import Settings
|
|
10
|
+
from ..utils.pagination import PaginationConfig, PaginationResult
|
|
9
11
|
from .base import BaseService
|
|
10
12
|
|
|
11
13
|
|
|
@@ -312,6 +314,29 @@ class DatasetService(BaseService):
|
|
|
312
314
|
except Exception as e:
|
|
313
315
|
raise RuntimeError(f"Failed to read dataset {dataset_rid}: {e}")
|
|
314
316
|
|
|
317
|
+
def preview_data(
|
|
318
|
+
self,
|
|
319
|
+
dataset_rid: str,
|
|
320
|
+
limit: int = 10,
|
|
321
|
+
) -> List[Dict[str, Any]]:
|
|
322
|
+
"""
|
|
323
|
+
Preview dataset contents as a list of records.
|
|
324
|
+
|
|
325
|
+
Args:
|
|
326
|
+
dataset_rid: Dataset Resource Identifier
|
|
327
|
+
limit: Maximum number of rows to return
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
List of dictionaries representing rows
|
|
331
|
+
"""
|
|
332
|
+
try:
|
|
333
|
+
# Use read_table with pandas format for easy conversion
|
|
334
|
+
df = self.read_table(dataset_rid, format="pandas")
|
|
335
|
+
# Limit rows and convert to records
|
|
336
|
+
return df.head(limit).to_dict(orient="records")
|
|
337
|
+
except Exception as e:
|
|
338
|
+
raise RuntimeError(f"Failed to preview dataset {dataset_rid}: {e}")
|
|
339
|
+
|
|
315
340
|
def delete_dataset(self, dataset_rid: str) -> bool:
|
|
316
341
|
"""
|
|
317
342
|
Delete a dataset.
|
|
@@ -516,6 +541,8 @@ class DatasetService(BaseService):
|
|
|
516
541
|
"""
|
|
517
542
|
List files in a dataset.
|
|
518
543
|
|
|
544
|
+
DEPRECATED: Use list_files_paginated() instead for better pagination support.
|
|
545
|
+
|
|
519
546
|
Args:
|
|
520
547
|
dataset_rid: Dataset Resource Identifier
|
|
521
548
|
branch: Dataset branch name
|
|
@@ -540,6 +567,53 @@ class DatasetService(BaseService):
|
|
|
540
567
|
except Exception as e:
|
|
541
568
|
raise RuntimeError(f"Failed to list files in dataset {dataset_rid}: {e}")
|
|
542
569
|
|
|
570
|
+
def list_files_paginated(
|
|
571
|
+
self,
|
|
572
|
+
dataset_rid: str,
|
|
573
|
+
branch: str,
|
|
574
|
+
config: PaginationConfig,
|
|
575
|
+
progress_callback: Optional[Callable[[int, int], None]] = None,
|
|
576
|
+
) -> PaginationResult:
|
|
577
|
+
"""
|
|
578
|
+
List files with full pagination control.
|
|
579
|
+
|
|
580
|
+
Args:
|
|
581
|
+
dataset_rid: Dataset Resource Identifier
|
|
582
|
+
branch: Dataset branch name
|
|
583
|
+
config: Pagination configuration
|
|
584
|
+
progress_callback: Optional progress callback
|
|
585
|
+
|
|
586
|
+
Returns:
|
|
587
|
+
PaginationResult with file information and metadata
|
|
588
|
+
"""
|
|
589
|
+
try:
|
|
590
|
+
settings = Settings()
|
|
591
|
+
|
|
592
|
+
# Get iterator from SDK - ResourceIterator with next_page_token support
|
|
593
|
+
iterator = self.service.Dataset.File.list(
|
|
594
|
+
dataset_rid=dataset_rid,
|
|
595
|
+
branch_name=branch,
|
|
596
|
+
page_size=config.page_size or settings.get("page_size", 20),
|
|
597
|
+
)
|
|
598
|
+
|
|
599
|
+
# Use iterator pagination handler
|
|
600
|
+
result = self._paginate_iterator(iterator, config, progress_callback)
|
|
601
|
+
|
|
602
|
+
# Format file information
|
|
603
|
+
result.data = [
|
|
604
|
+
{
|
|
605
|
+
"path": file.path,
|
|
606
|
+
"size_bytes": getattr(file, "size_bytes", None),
|
|
607
|
+
"last_modified": getattr(file, "last_modified", None),
|
|
608
|
+
"transaction_rid": getattr(file, "transaction_rid", None),
|
|
609
|
+
}
|
|
610
|
+
for file in result.data
|
|
611
|
+
]
|
|
612
|
+
|
|
613
|
+
return result
|
|
614
|
+
except Exception as e:
|
|
615
|
+
raise RuntimeError(f"Failed to list files: {e}")
|
|
616
|
+
|
|
543
617
|
def get_branches(self, dataset_rid: str) -> List[Dict[str, Any]]:
|
|
544
618
|
"""
|
|
545
619
|
Get list of branches for a dataset.
|
pltr/services/mediasets.py
CHANGED
|
@@ -226,15 +226,7 @@ class MediaSetsService(BaseService):
|
|
|
226
226
|
preview=preview,
|
|
227
227
|
)
|
|
228
228
|
|
|
229
|
-
|
|
230
|
-
if hasattr(response, "content"):
|
|
231
|
-
file.write(response.content)
|
|
232
|
-
else:
|
|
233
|
-
# Handle streaming response
|
|
234
|
-
for chunk in response:
|
|
235
|
-
file.write(chunk)
|
|
236
|
-
|
|
237
|
-
file_size = output_path_obj.stat().st_size
|
|
229
|
+
file_size = self._write_response_to_file(response, output_path_obj)
|
|
238
230
|
return {
|
|
239
231
|
"media_set_rid": media_set_rid,
|
|
240
232
|
"media_item_rid": media_item_rid,
|
|
@@ -291,3 +283,146 @@ class MediaSetsService(BaseService):
|
|
|
291
283
|
"url": getattr(reference_response, "url", "unknown"),
|
|
292
284
|
"expires_at": getattr(reference_response, "expires_at", None),
|
|
293
285
|
}
|
|
286
|
+
|
|
287
|
+
def _write_response_to_file(self, response: Any, output_path: Path) -> int:
|
|
288
|
+
"""
|
|
289
|
+
Write response content to file and return file size.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
response: SDK response object (with .content attribute or iterable)
|
|
293
|
+
output_path: Path object for the output file
|
|
294
|
+
|
|
295
|
+
Returns:
|
|
296
|
+
File size in bytes
|
|
297
|
+
"""
|
|
298
|
+
with open(output_path, "wb") as file:
|
|
299
|
+
if hasattr(response, "content"):
|
|
300
|
+
file.write(response.content)
|
|
301
|
+
else:
|
|
302
|
+
# Handle streaming response
|
|
303
|
+
for chunk in response:
|
|
304
|
+
file.write(chunk)
|
|
305
|
+
return output_path.stat().st_size
|
|
306
|
+
|
|
307
|
+
def calculate_thumbnail(
|
|
308
|
+
self,
|
|
309
|
+
media_set_rid: str,
|
|
310
|
+
media_item_rid: str,
|
|
311
|
+
preview: bool = False,
|
|
312
|
+
) -> Dict[str, Any]:
|
|
313
|
+
"""
|
|
314
|
+
Initiate thumbnail generation for an image.
|
|
315
|
+
|
|
316
|
+
Args:
|
|
317
|
+
media_set_rid: Media Set Resource Identifier
|
|
318
|
+
media_item_rid: Media Item Resource Identifier
|
|
319
|
+
preview: Enable preview mode
|
|
320
|
+
|
|
321
|
+
Returns:
|
|
322
|
+
Thumbnail calculation status information
|
|
323
|
+
"""
|
|
324
|
+
try:
|
|
325
|
+
response = self.service.MediaSet.calculate(
|
|
326
|
+
media_set_rid=media_set_rid,
|
|
327
|
+
media_item_rid=media_item_rid,
|
|
328
|
+
preview=preview,
|
|
329
|
+
)
|
|
330
|
+
return self._format_thumbnail_status(response)
|
|
331
|
+
except Exception as e:
|
|
332
|
+
raise RuntimeError(f"Failed to calculate thumbnail: {e}")
|
|
333
|
+
|
|
334
|
+
def retrieve_thumbnail(
|
|
335
|
+
self,
|
|
336
|
+
media_set_rid: str,
|
|
337
|
+
media_item_rid: str,
|
|
338
|
+
output_path: str,
|
|
339
|
+
preview: bool = False,
|
|
340
|
+
) -> Dict[str, Any]:
|
|
341
|
+
"""
|
|
342
|
+
Retrieve a calculated thumbnail (200px wide webp).
|
|
343
|
+
|
|
344
|
+
Args:
|
|
345
|
+
media_set_rid: Media Set Resource Identifier
|
|
346
|
+
media_item_rid: Media Item Resource Identifier
|
|
347
|
+
output_path: Local path where thumbnail should be saved
|
|
348
|
+
preview: Enable preview mode
|
|
349
|
+
|
|
350
|
+
Returns:
|
|
351
|
+
Download response information
|
|
352
|
+
"""
|
|
353
|
+
try:
|
|
354
|
+
output_path_obj = Path(output_path)
|
|
355
|
+
output_path_obj.parent.mkdir(parents=True, exist_ok=True)
|
|
356
|
+
|
|
357
|
+
response = self.service.MediaSet.retrieve(
|
|
358
|
+
media_set_rid=media_set_rid,
|
|
359
|
+
media_item_rid=media_item_rid,
|
|
360
|
+
preview=preview,
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
file_size = self._write_response_to_file(response, output_path_obj)
|
|
364
|
+
|
|
365
|
+
# Validate that we received actual content
|
|
366
|
+
if file_size == 0:
|
|
367
|
+
output_path_obj.unlink(missing_ok=True)
|
|
368
|
+
raise RuntimeError(
|
|
369
|
+
"Downloaded thumbnail is empty - thumbnail may not be ready yet"
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
return {
|
|
373
|
+
"media_set_rid": media_set_rid,
|
|
374
|
+
"media_item_rid": media_item_rid,
|
|
375
|
+
"output_path": str(output_path_obj),
|
|
376
|
+
"file_size": file_size,
|
|
377
|
+
"downloaded": True,
|
|
378
|
+
"format": "image/webp",
|
|
379
|
+
}
|
|
380
|
+
except Exception as e:
|
|
381
|
+
raise RuntimeError(f"Failed to retrieve thumbnail: {e}")
|
|
382
|
+
|
|
383
|
+
def upload_temp_media(
|
|
384
|
+
self,
|
|
385
|
+
file_path: str,
|
|
386
|
+
filename: Optional[str] = None,
|
|
387
|
+
attribution: Optional[str] = None,
|
|
388
|
+
preview: bool = False,
|
|
389
|
+
) -> Dict[str, Any]:
|
|
390
|
+
"""
|
|
391
|
+
Upload temporary media (auto-deleted after 1 hour if not persisted).
|
|
392
|
+
|
|
393
|
+
Args:
|
|
394
|
+
file_path: Local path to the file to upload
|
|
395
|
+
filename: Optional filename override
|
|
396
|
+
attribution: Optional attribution string
|
|
397
|
+
preview: Enable preview mode
|
|
398
|
+
|
|
399
|
+
Returns:
|
|
400
|
+
Media reference information
|
|
401
|
+
"""
|
|
402
|
+
try:
|
|
403
|
+
file_path_obj = Path(file_path)
|
|
404
|
+
if not file_path_obj.exists():
|
|
405
|
+
raise FileNotFoundError(f"File not found: {file_path}")
|
|
406
|
+
|
|
407
|
+
# Use provided filename or default to file name
|
|
408
|
+
upload_filename = filename or file_path_obj.name
|
|
409
|
+
|
|
410
|
+
with open(file_path_obj, "rb") as file:
|
|
411
|
+
response = self.service.MediaSet.upload_media(
|
|
412
|
+
body=file,
|
|
413
|
+
filename=upload_filename,
|
|
414
|
+
attribution=attribution,
|
|
415
|
+
preview=preview,
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
return self._format_media_reference(response)
|
|
419
|
+
except Exception as e:
|
|
420
|
+
raise RuntimeError(f"Failed to upload temporary media: {e}")
|
|
421
|
+
|
|
422
|
+
def _format_thumbnail_status(self, status_response: Any) -> Dict[str, Any]:
|
|
423
|
+
"""Format thumbnail calculation status response for display."""
|
|
424
|
+
return {
|
|
425
|
+
"status": getattr(status_response, "status", "unknown"),
|
|
426
|
+
"transformation_id": getattr(status_response, "transformation_id", None),
|
|
427
|
+
"media_item_rid": getattr(status_response, "media_item_rid", None),
|
|
428
|
+
}
|
pltr/services/ontology.py
CHANGED
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
Ontology service wrappers for Foundry SDK.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from typing import Any,
|
|
5
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
from ..config.settings import Settings
|
|
8
|
+
from ..utils.pagination import PaginationConfig, PaginationResult
|
|
6
9
|
from .base import BaseService
|
|
7
10
|
|
|
8
11
|
|
|
@@ -165,6 +168,8 @@ class OntologyObjectService(BaseService):
|
|
|
165
168
|
"""
|
|
166
169
|
List objects of a specific type.
|
|
167
170
|
|
|
171
|
+
DEPRECATED: Use list_objects_paginated() instead for better pagination support.
|
|
172
|
+
|
|
168
173
|
Args:
|
|
169
174
|
ontology_rid: Ontology Resource Identifier
|
|
170
175
|
object_type: Object type API name
|
|
@@ -188,6 +193,48 @@ class OntologyObjectService(BaseService):
|
|
|
188
193
|
except Exception as e:
|
|
189
194
|
raise RuntimeError(f"Failed to list objects: {e}")
|
|
190
195
|
|
|
196
|
+
def list_objects_paginated(
|
|
197
|
+
self,
|
|
198
|
+
ontology_rid: str,
|
|
199
|
+
object_type: str,
|
|
200
|
+
config: PaginationConfig,
|
|
201
|
+
properties: Optional[List[str]] = None,
|
|
202
|
+
progress_callback: Optional[Callable[[int, int], None]] = None,
|
|
203
|
+
) -> PaginationResult:
|
|
204
|
+
"""
|
|
205
|
+
List objects with full pagination control.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
ontology_rid: Ontology Resource Identifier
|
|
209
|
+
object_type: Object type API name
|
|
210
|
+
config: Pagination configuration
|
|
211
|
+
properties: List of properties to include
|
|
212
|
+
progress_callback: Optional progress callback
|
|
213
|
+
|
|
214
|
+
Returns:
|
|
215
|
+
PaginationResult with objects and metadata
|
|
216
|
+
"""
|
|
217
|
+
try:
|
|
218
|
+
settings = Settings()
|
|
219
|
+
|
|
220
|
+
# Get iterator from SDK - ResourceIterator with next_page_token support
|
|
221
|
+
iterator = self.service.OntologyObject.list(
|
|
222
|
+
ontology_rid,
|
|
223
|
+
object_type,
|
|
224
|
+
page_size=config.page_size or settings.get("page_size", 20),
|
|
225
|
+
properties=properties,
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
# Use iterator pagination handler
|
|
229
|
+
result = self._paginate_iterator(iterator, config, progress_callback)
|
|
230
|
+
|
|
231
|
+
# Format objects
|
|
232
|
+
result.data = [self._format_object(obj) for obj in result.data]
|
|
233
|
+
|
|
234
|
+
return result
|
|
235
|
+
except Exception as e:
|
|
236
|
+
raise RuntimeError(f"Failed to list objects: {e}")
|
|
237
|
+
|
|
191
238
|
def get_object(
|
|
192
239
|
self,
|
|
193
240
|
ontology_rid: str,
|
pltr/services/orchestration.py
CHANGED
|
@@ -3,8 +3,10 @@ Orchestration service wrapper for Foundry SDK v2 API.
|
|
|
3
3
|
Provides operations for managing builds, jobs, and schedules.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
from typing import Any,
|
|
6
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
7
7
|
|
|
8
|
+
from ..config.settings import Settings
|
|
9
|
+
from ..utils.pagination import PaginationConfig, PaginationResult
|
|
8
10
|
from .base import BaseService
|
|
9
11
|
|
|
10
12
|
|
|
@@ -134,6 +136,8 @@ class OrchestrationService(BaseService):
|
|
|
134
136
|
"""
|
|
135
137
|
Search for builds.
|
|
136
138
|
|
|
139
|
+
DEPRECATED: Use search_builds_paginated() instead for better pagination support.
|
|
140
|
+
|
|
137
141
|
Args:
|
|
138
142
|
page_size: Number of results per page
|
|
139
143
|
page_token: Token for pagination
|
|
@@ -155,6 +159,63 @@ class OrchestrationService(BaseService):
|
|
|
155
159
|
except Exception as e:
|
|
156
160
|
raise RuntimeError(f"Failed to search builds: {e}")
|
|
157
161
|
|
|
162
|
+
def search_builds_paginated(
|
|
163
|
+
self,
|
|
164
|
+
config: PaginationConfig,
|
|
165
|
+
progress_callback: Optional[Callable[[int, int], None]] = None,
|
|
166
|
+
**search_params,
|
|
167
|
+
) -> PaginationResult:
|
|
168
|
+
"""
|
|
169
|
+
Search for builds with full pagination control.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
config: Pagination configuration
|
|
173
|
+
progress_callback: Optional progress callback
|
|
174
|
+
**search_params: Additional search parameters
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
PaginationResult with builds and metadata
|
|
178
|
+
"""
|
|
179
|
+
try:
|
|
180
|
+
settings = Settings()
|
|
181
|
+
|
|
182
|
+
def fetch_page(page_token: Optional[str]) -> Dict[str, Any]:
|
|
183
|
+
"""Fetch a single page of builds."""
|
|
184
|
+
kwargs: Dict[str, Any] = {
|
|
185
|
+
"page_size": config.page_size or settings.get("page_size", 20),
|
|
186
|
+
}
|
|
187
|
+
if page_token:
|
|
188
|
+
kwargs["page_token"] = page_token
|
|
189
|
+
kwargs.update(search_params)
|
|
190
|
+
|
|
191
|
+
response = self.service.Build.search(**kwargs)
|
|
192
|
+
return self._format_builds_search_response(response)
|
|
193
|
+
|
|
194
|
+
return self._paginate_response(fetch_page, config, progress_callback)
|
|
195
|
+
except Exception as e:
|
|
196
|
+
raise RuntimeError(f"Failed to search builds: {e}")
|
|
197
|
+
|
|
198
|
+
def get_builds_batch(self, build_rids: List[str]) -> Dict[str, Any]:
|
|
199
|
+
"""
|
|
200
|
+
Get multiple builds in batch.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
build_rids: List of Build Resource Identifiers (max 100)
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
Batch response with build information
|
|
207
|
+
"""
|
|
208
|
+
if len(build_rids) > 100:
|
|
209
|
+
raise ValueError("Maximum batch size is 100 builds")
|
|
210
|
+
|
|
211
|
+
try:
|
|
212
|
+
# SDK expects list of {"rid": ...} objects for batch operations
|
|
213
|
+
body = [{"rid": rid} for rid in build_rids]
|
|
214
|
+
response = self.service.Build.get_batch(body)
|
|
215
|
+
return self._format_builds_batch_response(response)
|
|
216
|
+
except Exception as e:
|
|
217
|
+
raise RuntimeError(f"Failed to get builds batch: {e}")
|
|
218
|
+
|
|
158
219
|
# Job operations
|
|
159
220
|
def get_job(self, job_rid: str) -> Dict[str, Any]:
|
|
160
221
|
"""
|
|
@@ -353,6 +414,35 @@ class OrchestrationService(BaseService):
|
|
|
353
414
|
except Exception as e:
|
|
354
415
|
raise RuntimeError(f"Failed to replace schedule {schedule_rid}: {e}")
|
|
355
416
|
|
|
417
|
+
def get_schedule_runs(
|
|
418
|
+
self,
|
|
419
|
+
schedule_rid: str,
|
|
420
|
+
page_size: Optional[int] = None,
|
|
421
|
+
page_token: Optional[str] = None,
|
|
422
|
+
) -> Dict[str, Any]:
|
|
423
|
+
"""
|
|
424
|
+
Get recent execution runs for a schedule.
|
|
425
|
+
|
|
426
|
+
Args:
|
|
427
|
+
schedule_rid: Schedule Resource Identifier
|
|
428
|
+
page_size: Number of results per page
|
|
429
|
+
page_token: Token for pagination
|
|
430
|
+
|
|
431
|
+
Returns:
|
|
432
|
+
Runs list with pagination info
|
|
433
|
+
"""
|
|
434
|
+
try:
|
|
435
|
+
kwargs: Dict[str, Any] = {"schedule_rid": schedule_rid}
|
|
436
|
+
if page_size is not None:
|
|
437
|
+
kwargs["page_size"] = page_size
|
|
438
|
+
if page_token is not None:
|
|
439
|
+
kwargs["page_token"] = page_token
|
|
440
|
+
|
|
441
|
+
response = self.service.Schedule.runs(**kwargs)
|
|
442
|
+
return self._format_schedule_runs_response(response)
|
|
443
|
+
except Exception as e:
|
|
444
|
+
raise RuntimeError(f"Failed to get runs for schedule {schedule_rid}: {e}")
|
|
445
|
+
|
|
356
446
|
# Formatting methods
|
|
357
447
|
def _format_build_info(self, build: Any) -> Dict[str, Any]:
|
|
358
448
|
"""Format build information for consistent output."""
|
|
@@ -455,3 +545,45 @@ class OrchestrationService(BaseService):
|
|
|
455
545
|
result["jobs"].append(self._format_job_info(item.data))
|
|
456
546
|
|
|
457
547
|
return result
|
|
548
|
+
|
|
549
|
+
def _format_builds_batch_response(self, response: Any) -> Dict[str, Any]:
|
|
550
|
+
"""Format builds batch response."""
|
|
551
|
+
result: Dict[str, Any] = {"builds": []}
|
|
552
|
+
|
|
553
|
+
if hasattr(response, "data"):
|
|
554
|
+
for item in response.data:
|
|
555
|
+
if hasattr(item, "data"):
|
|
556
|
+
result["builds"].append(self._format_build_info(item.data))
|
|
557
|
+
|
|
558
|
+
return result
|
|
559
|
+
|
|
560
|
+
def _format_run_info(self, run: Any) -> Dict[str, Any]:
|
|
561
|
+
"""Format schedule run information for consistent output."""
|
|
562
|
+
info = {}
|
|
563
|
+
|
|
564
|
+
for attr in [
|
|
565
|
+
"rid",
|
|
566
|
+
"schedule_rid",
|
|
567
|
+
"status",
|
|
568
|
+
"created_time",
|
|
569
|
+
"started_time",
|
|
570
|
+
"finished_time",
|
|
571
|
+
"build_rid",
|
|
572
|
+
"result",
|
|
573
|
+
]:
|
|
574
|
+
if hasattr(run, attr):
|
|
575
|
+
info[attr] = getattr(run, attr)
|
|
576
|
+
|
|
577
|
+
return info
|
|
578
|
+
|
|
579
|
+
def _format_schedule_runs_response(self, response: Any) -> Dict[str, Any]:
|
|
580
|
+
"""Format schedule runs response."""
|
|
581
|
+
result: Dict[str, Any] = {"runs": []}
|
|
582
|
+
|
|
583
|
+
if hasattr(response, "data"):
|
|
584
|
+
result["runs"] = [self._format_run_info(run) for run in response.data]
|
|
585
|
+
|
|
586
|
+
if hasattr(response, "next_page_token"):
|
|
587
|
+
result["next_page_token"] = response.next_page_token
|
|
588
|
+
|
|
589
|
+
return result
|
pltr/services/project.py
CHANGED
|
@@ -185,6 +185,126 @@ class ProjectService(BaseService):
|
|
|
185
185
|
except Exception as e:
|
|
186
186
|
raise RuntimeError(f"Failed to get projects batch: {e}")
|
|
187
187
|
|
|
188
|
+
# ==================== Organization Operations ====================
|
|
189
|
+
|
|
190
|
+
def add_organizations(self, project_rid: str, organization_rids: List[str]) -> None:
|
|
191
|
+
"""
|
|
192
|
+
Add organizations to a project.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
project_rid: Project Resource Identifier
|
|
196
|
+
organization_rids: List of organization RIDs to add
|
|
197
|
+
|
|
198
|
+
Raises:
|
|
199
|
+
RuntimeError: If adding organizations fails
|
|
200
|
+
"""
|
|
201
|
+
try:
|
|
202
|
+
self.service.Project.add_organizations(
|
|
203
|
+
project_rid, organization_rids=organization_rids, preview=True
|
|
204
|
+
)
|
|
205
|
+
except Exception as e:
|
|
206
|
+
raise RuntimeError(
|
|
207
|
+
f"Failed to add organizations to project {project_rid}: {e}"
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
def remove_organizations(
|
|
211
|
+
self, project_rid: str, organization_rids: List[str]
|
|
212
|
+
) -> None:
|
|
213
|
+
"""
|
|
214
|
+
Remove organizations from a project.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
project_rid: Project Resource Identifier
|
|
218
|
+
organization_rids: List of organization RIDs to remove
|
|
219
|
+
|
|
220
|
+
Raises:
|
|
221
|
+
RuntimeError: If removing organizations fails
|
|
222
|
+
"""
|
|
223
|
+
try:
|
|
224
|
+
self.service.Project.remove_organizations(
|
|
225
|
+
project_rid, organization_rids=organization_rids, preview=True
|
|
226
|
+
)
|
|
227
|
+
except Exception as e:
|
|
228
|
+
raise RuntimeError(
|
|
229
|
+
f"Failed to remove organizations from project {project_rid}: {e}"
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
def list_organizations(
|
|
233
|
+
self,
|
|
234
|
+
project_rid: str,
|
|
235
|
+
page_size: Optional[int] = None,
|
|
236
|
+
page_token: Optional[str] = None,
|
|
237
|
+
) -> List[Dict[str, Any]]:
|
|
238
|
+
"""
|
|
239
|
+
List organizations directly applied to a project.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
project_rid: Project Resource Identifier
|
|
243
|
+
page_size: Number of items per page (optional)
|
|
244
|
+
page_token: Pagination token (optional)
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
List of organization information dictionaries
|
|
248
|
+
"""
|
|
249
|
+
try:
|
|
250
|
+
organizations = []
|
|
251
|
+
list_params: Dict[str, Any] = {"preview": True}
|
|
252
|
+
|
|
253
|
+
if page_size:
|
|
254
|
+
list_params["page_size"] = page_size
|
|
255
|
+
if page_token:
|
|
256
|
+
list_params["page_token"] = page_token
|
|
257
|
+
|
|
258
|
+
for org in self.service.Project.organizations(project_rid, **list_params):
|
|
259
|
+
organizations.append(self._format_organization_info(org))
|
|
260
|
+
return organizations
|
|
261
|
+
except Exception as e:
|
|
262
|
+
raise RuntimeError(
|
|
263
|
+
f"Failed to list organizations for project {project_rid}: {e}"
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
# ==================== Template Operations ====================
|
|
267
|
+
|
|
268
|
+
def create_project_from_template(
|
|
269
|
+
self,
|
|
270
|
+
template_rid: str,
|
|
271
|
+
variable_values: Dict[str, str],
|
|
272
|
+
default_roles: Optional[List[str]] = None,
|
|
273
|
+
organization_rids: Optional[List[str]] = None,
|
|
274
|
+
project_description: Optional[str] = None,
|
|
275
|
+
) -> Dict[str, Any]:
|
|
276
|
+
"""
|
|
277
|
+
Create a project from a template.
|
|
278
|
+
|
|
279
|
+
Args:
|
|
280
|
+
template_rid: Template Resource Identifier
|
|
281
|
+
variable_values: Dictionary mapping template variable names to values
|
|
282
|
+
default_roles: List of default role names (optional)
|
|
283
|
+
organization_rids: List of organization RIDs (optional)
|
|
284
|
+
project_description: Project description (optional)
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
Created project information
|
|
288
|
+
"""
|
|
289
|
+
try:
|
|
290
|
+
create_params: Dict[str, Any] = {
|
|
291
|
+
"template_rid": template_rid,
|
|
292
|
+
"variable_values": variable_values,
|
|
293
|
+
"preview": True,
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if default_roles:
|
|
297
|
+
create_params["default_roles"] = default_roles
|
|
298
|
+
if organization_rids:
|
|
299
|
+
create_params["organization_rids"] = organization_rids
|
|
300
|
+
if project_description:
|
|
301
|
+
create_params["project_description"] = project_description
|
|
302
|
+
|
|
303
|
+
project = self.service.Project.create_from_template(**create_params)
|
|
304
|
+
return self._format_project_info(project)
|
|
305
|
+
except Exception as e:
|
|
306
|
+
raise RuntimeError(f"Failed to create project from template: {e}")
|
|
307
|
+
|
|
188
308
|
def _format_project_info(self, project: Any) -> Dict[str, Any]:
|
|
189
309
|
"""
|
|
190
310
|
Format project information for consistent output.
|
|
@@ -213,6 +333,22 @@ class ProjectService(BaseService):
|
|
|
213
333
|
"type": "project",
|
|
214
334
|
}
|
|
215
335
|
|
|
336
|
+
def _format_organization_info(self, organization: Any) -> Dict[str, Any]:
|
|
337
|
+
"""
|
|
338
|
+
Format organization information for consistent output.
|
|
339
|
+
|
|
340
|
+
Args:
|
|
341
|
+
organization: Organization object from Foundry SDK
|
|
342
|
+
|
|
343
|
+
Returns:
|
|
344
|
+
Formatted organization information dictionary
|
|
345
|
+
"""
|
|
346
|
+
return {
|
|
347
|
+
"organization_rid": getattr(organization, "organization_rid", None),
|
|
348
|
+
"display_name": getattr(organization, "display_name", None),
|
|
349
|
+
"description": getattr(organization, "description", None),
|
|
350
|
+
}
|
|
351
|
+
|
|
216
352
|
def _format_timestamp(self, timestamp: Any) -> Optional[str]:
|
|
217
353
|
"""
|
|
218
354
|
Format timestamp for display.
|