pltr-cli 0.4.0__py3-none-any.whl → 0.5.1__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.
@@ -0,0 +1,457 @@
1
+ """
2
+ Orchestration service wrapper for Foundry SDK v2 API.
3
+ Provides operations for managing builds, jobs, and schedules.
4
+ """
5
+
6
+ from typing import Any, Optional, Dict, List
7
+
8
+ from .base import BaseService
9
+
10
+
11
+ class OrchestrationService(BaseService):
12
+ """Service wrapper for Foundry orchestration operations using v2 API."""
13
+
14
+ def _get_service(self) -> Any:
15
+ """Get the Foundry orchestration service."""
16
+ return self.client.orchestration
17
+
18
+ # Build operations
19
+ def get_build(self, build_rid: str) -> Dict[str, Any]:
20
+ """
21
+ Get information about a specific build.
22
+
23
+ Args:
24
+ build_rid: Build Resource Identifier
25
+
26
+ Returns:
27
+ Build information dictionary
28
+ """
29
+ try:
30
+ build = self.service.Build.get(build_rid)
31
+ return self._format_build_info(build)
32
+ except Exception as e:
33
+ raise RuntimeError(f"Failed to get build {build_rid}: {e}")
34
+
35
+ def create_build(
36
+ self,
37
+ target: Dict[str, Any],
38
+ fallback_branches: Optional[Dict[str, Any]] = None,
39
+ abort_on_failure: Optional[bool] = None,
40
+ branch_name: Optional[str] = None,
41
+ force_build: Optional[bool] = None,
42
+ notifications_enabled: Optional[bool] = None,
43
+ retry_backoff_duration: Optional[int] = None,
44
+ retry_count: Optional[int] = None,
45
+ ) -> Dict[str, Any]:
46
+ """
47
+ Create a new build.
48
+
49
+ Args:
50
+ target: Build target configuration
51
+ fallback_branches: Fallback branches configuration
52
+ abort_on_failure: Whether to abort on failure
53
+ branch_name: Branch name for the build
54
+ force_build: Force build even if no changes
55
+ notifications_enabled: Enable notifications
56
+ retry_backoff_duration: Retry backoff duration in milliseconds
57
+ retry_count: Number of retries
58
+
59
+ Returns:
60
+ Created build information
61
+ """
62
+ try:
63
+ kwargs: Dict[str, Any] = {
64
+ "target": target,
65
+ "fallback_branches": fallback_branches or {},
66
+ }
67
+
68
+ # Add optional parameters if provided
69
+ if abort_on_failure is not None:
70
+ kwargs["abort_on_failure"] = abort_on_failure
71
+ if branch_name is not None:
72
+ kwargs["branch_name"] = branch_name
73
+ if force_build is not None:
74
+ kwargs["force_build"] = force_build
75
+ if notifications_enabled is not None:
76
+ kwargs["notifications_enabled"] = notifications_enabled
77
+ if retry_backoff_duration is not None:
78
+ kwargs["retry_backoff_duration"] = retry_backoff_duration
79
+ if retry_count is not None:
80
+ kwargs["retry_count"] = retry_count
81
+
82
+ build = self.service.Build.create(**kwargs)
83
+ return self._format_build_info(build)
84
+ except Exception as e:
85
+ raise RuntimeError(f"Failed to create build: {e}")
86
+
87
+ def cancel_build(self, build_rid: str) -> None:
88
+ """
89
+ Cancel a build.
90
+
91
+ Args:
92
+ build_rid: Build Resource Identifier
93
+ """
94
+ try:
95
+ self.service.Build.cancel(build_rid)
96
+ except Exception as e:
97
+ raise RuntimeError(f"Failed to cancel build {build_rid}: {e}")
98
+
99
+ def get_build_jobs(
100
+ self,
101
+ build_rid: str,
102
+ page_size: Optional[int] = None,
103
+ page_token: Optional[str] = None,
104
+ ) -> Dict[str, Any]:
105
+ """
106
+ Get jobs in a build.
107
+
108
+ Args:
109
+ build_rid: Build Resource Identifier
110
+ page_size: Number of results per page
111
+ page_token: Token for pagination
112
+
113
+ Returns:
114
+ Jobs list with pagination info
115
+ """
116
+ try:
117
+ kwargs: Dict[str, Any] = {"build_rid": build_rid}
118
+ if page_size is not None:
119
+ kwargs["page_size"] = page_size
120
+ if page_token is not None:
121
+ kwargs["page_token"] = page_token
122
+
123
+ response = self.service.Build.jobs(**kwargs)
124
+ return self._format_jobs_response(response)
125
+ except Exception as e:
126
+ raise RuntimeError(f"Failed to get jobs for build {build_rid}: {e}")
127
+
128
+ def search_builds(
129
+ self,
130
+ page_size: Optional[int] = None,
131
+ page_token: Optional[str] = None,
132
+ **search_params,
133
+ ) -> Dict[str, Any]:
134
+ """
135
+ Search for builds.
136
+
137
+ Args:
138
+ page_size: Number of results per page
139
+ page_token: Token for pagination
140
+ **search_params: Additional search parameters
141
+
142
+ Returns:
143
+ Search results with pagination info
144
+ """
145
+ try:
146
+ kwargs: Dict[str, Any] = {}
147
+ if page_size is not None:
148
+ kwargs["page_size"] = page_size
149
+ if page_token is not None:
150
+ kwargs["page_token"] = page_token
151
+ kwargs.update(search_params)
152
+
153
+ response = self.service.Build.search(**kwargs)
154
+ return self._format_builds_search_response(response)
155
+ except Exception as e:
156
+ raise RuntimeError(f"Failed to search builds: {e}")
157
+
158
+ # Job operations
159
+ def get_job(self, job_rid: str) -> Dict[str, Any]:
160
+ """
161
+ Get information about a specific job.
162
+
163
+ Args:
164
+ job_rid: Job Resource Identifier
165
+
166
+ Returns:
167
+ Job information dictionary
168
+ """
169
+ try:
170
+ job = self.service.Job.get(job_rid)
171
+ return self._format_job_info(job)
172
+ except Exception as e:
173
+ raise RuntimeError(f"Failed to get job {job_rid}: {e}")
174
+
175
+ def get_jobs_batch(self, job_rids: List[str]) -> Dict[str, Any]:
176
+ """
177
+ Get multiple jobs in batch.
178
+
179
+ Args:
180
+ job_rids: List of Job Resource Identifiers (max 500)
181
+
182
+ Returns:
183
+ Batch response with job information
184
+ """
185
+ try:
186
+ if len(job_rids) > 500:
187
+ raise ValueError("Maximum batch size is 500 jobs")
188
+
189
+ body = [{"rid": rid} for rid in job_rids]
190
+ response = self.service.Job.get_batch(body)
191
+ return self._format_jobs_batch_response(response)
192
+ except Exception as e:
193
+ raise RuntimeError(f"Failed to get jobs batch: {e}")
194
+
195
+ # Schedule operations
196
+ def get_schedule(
197
+ self, schedule_rid: str, preview: Optional[bool] = None
198
+ ) -> Dict[str, Any]:
199
+ """
200
+ Get information about a specific schedule.
201
+
202
+ Args:
203
+ schedule_rid: Schedule Resource Identifier
204
+ preview: Enable preview mode
205
+
206
+ Returns:
207
+ Schedule information dictionary
208
+ """
209
+ try:
210
+ kwargs: Dict[str, Any] = {"schedule_rid": schedule_rid}
211
+ if preview is not None:
212
+ kwargs["preview"] = preview
213
+
214
+ schedule = self.service.Schedule.get(**kwargs)
215
+ return self._format_schedule_info(schedule)
216
+ except Exception as e:
217
+ raise RuntimeError(f"Failed to get schedule {schedule_rid}: {e}")
218
+
219
+ def create_schedule(
220
+ self,
221
+ action: Dict[str, Any],
222
+ description: Optional[str] = None,
223
+ display_name: Optional[str] = None,
224
+ trigger: Optional[Dict[str, Any]] = None,
225
+ scope_mode: Optional[str] = None,
226
+ preview: Optional[bool] = None,
227
+ ) -> Dict[str, Any]:
228
+ """
229
+ Create a new schedule.
230
+
231
+ Args:
232
+ action: Schedule action configuration
233
+ description: Schedule description
234
+ display_name: Display name for the schedule
235
+ trigger: Trigger configuration
236
+ scope_mode: Scope mode for the schedule
237
+ preview: Enable preview mode
238
+
239
+ Returns:
240
+ Created schedule information
241
+ """
242
+ try:
243
+ kwargs: Dict[str, Any] = {"action": action}
244
+
245
+ if description is not None:
246
+ kwargs["description"] = description
247
+ if display_name is not None:
248
+ kwargs["display_name"] = display_name
249
+ if trigger is not None:
250
+ kwargs["trigger"] = trigger
251
+ if scope_mode is not None:
252
+ kwargs["scope_mode"] = scope_mode
253
+ if preview is not None:
254
+ kwargs["preview"] = preview
255
+
256
+ schedule = self.service.Schedule.create(**kwargs)
257
+ return self._format_schedule_info(schedule)
258
+ except Exception as e:
259
+ raise RuntimeError(f"Failed to create schedule: {e}")
260
+
261
+ def delete_schedule(self, schedule_rid: str) -> None:
262
+ """
263
+ Delete a schedule.
264
+
265
+ Args:
266
+ schedule_rid: Schedule Resource Identifier
267
+ """
268
+ try:
269
+ self.service.Schedule.delete(schedule_rid)
270
+ except Exception as e:
271
+ raise RuntimeError(f"Failed to delete schedule {schedule_rid}: {e}")
272
+
273
+ def pause_schedule(self, schedule_rid: str) -> None:
274
+ """
275
+ Pause a schedule.
276
+
277
+ Args:
278
+ schedule_rid: Schedule Resource Identifier
279
+ """
280
+ try:
281
+ self.service.Schedule.pause(schedule_rid)
282
+ except Exception as e:
283
+ raise RuntimeError(f"Failed to pause schedule {schedule_rid}: {e}")
284
+
285
+ def unpause_schedule(self, schedule_rid: str) -> None:
286
+ """
287
+ Unpause a schedule.
288
+
289
+ Args:
290
+ schedule_rid: Schedule Resource Identifier
291
+ """
292
+ try:
293
+ self.service.Schedule.unpause(schedule_rid)
294
+ except Exception as e:
295
+ raise RuntimeError(f"Failed to unpause schedule {schedule_rid}: {e}")
296
+
297
+ def run_schedule(self, schedule_rid: str) -> None:
298
+ """
299
+ Execute a schedule immediately.
300
+
301
+ Args:
302
+ schedule_rid: Schedule Resource Identifier
303
+ """
304
+ try:
305
+ self.service.Schedule.run(schedule_rid)
306
+ except Exception as e:
307
+ raise RuntimeError(f"Failed to run schedule {schedule_rid}: {e}")
308
+
309
+ def replace_schedule(
310
+ self,
311
+ schedule_rid: str,
312
+ action: Dict[str, Any],
313
+ description: Optional[str] = None,
314
+ display_name: Optional[str] = None,
315
+ trigger: Optional[Dict[str, Any]] = None,
316
+ scope_mode: Optional[str] = None,
317
+ preview: Optional[bool] = None,
318
+ ) -> Dict[str, Any]:
319
+ """
320
+ Replace an existing schedule.
321
+
322
+ Args:
323
+ schedule_rid: Schedule Resource Identifier
324
+ action: Schedule action configuration
325
+ description: Schedule description
326
+ display_name: Display name for the schedule
327
+ trigger: Trigger configuration
328
+ scope_mode: Scope mode for the schedule
329
+ preview: Enable preview mode
330
+
331
+ Returns:
332
+ Updated schedule information
333
+ """
334
+ try:
335
+ kwargs: Dict[str, Any] = {
336
+ "schedule_rid": schedule_rid,
337
+ "action": action,
338
+ }
339
+
340
+ if description is not None:
341
+ kwargs["description"] = description
342
+ if display_name is not None:
343
+ kwargs["display_name"] = display_name
344
+ if trigger is not None:
345
+ kwargs["trigger"] = trigger
346
+ if scope_mode is not None:
347
+ kwargs["scope_mode"] = scope_mode
348
+ if preview is not None:
349
+ kwargs["preview"] = preview
350
+
351
+ schedule = self.service.Schedule.replace(**kwargs)
352
+ return self._format_schedule_info(schedule)
353
+ except Exception as e:
354
+ raise RuntimeError(f"Failed to replace schedule {schedule_rid}: {e}")
355
+
356
+ # Formatting methods
357
+ def _format_build_info(self, build: Any) -> Dict[str, Any]:
358
+ """Format build information for consistent output."""
359
+ info = {}
360
+
361
+ # Extract available attributes
362
+ for attr in [
363
+ "rid",
364
+ "status",
365
+ "created_time",
366
+ "started_time",
367
+ "finished_time",
368
+ "created_by",
369
+ "branch_name",
370
+ "commit_hash",
371
+ ]:
372
+ if hasattr(build, attr):
373
+ info[attr] = getattr(build, attr)
374
+
375
+ return info
376
+
377
+ def _format_job_info(self, job: Any) -> Dict[str, Any]:
378
+ """Format job information for consistent output."""
379
+ info = {}
380
+
381
+ # Extract available attributes
382
+ for attr in [
383
+ "rid",
384
+ "status",
385
+ "created_time",
386
+ "started_time",
387
+ "finished_time",
388
+ "job_type",
389
+ "build_rid",
390
+ ]:
391
+ if hasattr(job, attr):
392
+ info[attr] = getattr(job, attr)
393
+
394
+ return info
395
+
396
+ def _format_schedule_info(self, schedule: Any) -> Dict[str, Any]:
397
+ """Format schedule information for consistent output."""
398
+ info = {}
399
+
400
+ # Extract available attributes
401
+ for attr in [
402
+ "rid",
403
+ "display_name",
404
+ "description",
405
+ "paused",
406
+ "created_time",
407
+ "created_by",
408
+ "modified_time",
409
+ "modified_by",
410
+ ]:
411
+ if hasattr(schedule, attr):
412
+ info[attr] = getattr(schedule, attr)
413
+
414
+ # Handle nested objects
415
+ if hasattr(schedule, "trigger"):
416
+ info["trigger"] = str(schedule.trigger)
417
+ if hasattr(schedule, "action"):
418
+ info["action"] = str(schedule.action)
419
+
420
+ return info
421
+
422
+ def _format_jobs_response(self, response: Any) -> Dict[str, Any]:
423
+ """Format jobs list response."""
424
+ result: Dict[str, Any] = {"jobs": []}
425
+
426
+ if hasattr(response, "data"):
427
+ result["jobs"] = [self._format_job_info(job) for job in response.data]
428
+
429
+ if hasattr(response, "next_page_token"):
430
+ result["next_page_token"] = response.next_page_token
431
+
432
+ return result
433
+
434
+ def _format_builds_search_response(self, response: Any) -> Dict[str, Any]:
435
+ """Format builds search response."""
436
+ result: Dict[str, Any] = {"builds": []}
437
+
438
+ if hasattr(response, "data"):
439
+ result["builds"] = [
440
+ self._format_build_info(build) for build in response.data
441
+ ]
442
+
443
+ if hasattr(response, "next_page_token"):
444
+ result["next_page_token"] = response.next_page_token
445
+
446
+ return result
447
+
448
+ def _format_jobs_batch_response(self, response: Any) -> Dict[str, Any]:
449
+ """Format jobs batch response."""
450
+ result: Dict[str, Any] = {"jobs": []}
451
+
452
+ if hasattr(response, "data"):
453
+ for item in response.data:
454
+ if hasattr(item, "data"):
455
+ result["jobs"].append(self._format_job_info(item.data))
456
+
457
+ return result
@@ -0,0 +1,232 @@
1
+ """
2
+ Project 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 ProjectService(BaseService):
11
+ """Service wrapper for Foundry project 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_project(
18
+ self,
19
+ display_name: str,
20
+ space_rid: str,
21
+ description: Optional[str] = None,
22
+ organization_rids: Optional[List[str]] = None,
23
+ default_roles: Optional[List[str]] = None,
24
+ role_grants: Optional[List[Dict[str, Any]]] = None,
25
+ ) -> Dict[str, Any]:
26
+ """
27
+ Create a new project.
28
+
29
+ Args:
30
+ display_name: Project display name (cannot contain '/')
31
+ space_rid: Space Resource Identifier where project will be created
32
+ description: Project description (optional)
33
+ organization_rids: List of organization RIDs (optional)
34
+ default_roles: List of default role names (optional)
35
+ role_grants: List of role grant specifications (optional)
36
+
37
+ Returns:
38
+ Created project information
39
+ """
40
+ try:
41
+ # Prepare the create request payload
42
+ create_request: Dict[str, Any] = {
43
+ "display_name": display_name,
44
+ "space_rid": space_rid,
45
+ }
46
+
47
+ if description:
48
+ create_request["description"] = description
49
+ if organization_rids:
50
+ create_request["organization_rids"] = organization_rids
51
+ if default_roles:
52
+ create_request["default_roles"] = default_roles
53
+ if role_grants:
54
+ create_request["role_grants"] = role_grants
55
+
56
+ project = self.service.Project.create(
57
+ body=create_request,
58
+ preview=True,
59
+ )
60
+ return self._format_project_info(project)
61
+ except Exception as e:
62
+ raise RuntimeError(f"Failed to create project '{display_name}': {e}")
63
+
64
+ def get_project(self, project_rid: str) -> Dict[str, Any]:
65
+ """
66
+ Get information about a specific project.
67
+
68
+ Args:
69
+ project_rid: Project Resource Identifier
70
+
71
+ Returns:
72
+ Project information dictionary
73
+ """
74
+ try:
75
+ project = self.service.Project.get(project_rid, preview=True)
76
+ return self._format_project_info(project)
77
+ except Exception as e:
78
+ raise RuntimeError(f"Failed to get project {project_rid}: {e}")
79
+
80
+ def list_projects(
81
+ self,
82
+ space_rid: Optional[str] = None,
83
+ page_size: Optional[int] = None,
84
+ page_token: Optional[str] = None,
85
+ ) -> List[Dict[str, Any]]:
86
+ """
87
+ List projects, optionally filtered by space.
88
+
89
+ Args:
90
+ space_rid: Space Resource Identifier to filter by (optional)
91
+ page_size: Number of items per page (optional)
92
+ page_token: Pagination token (optional)
93
+
94
+ Returns:
95
+ List of project information dictionaries
96
+ """
97
+ try:
98
+ projects = []
99
+ list_params: Dict[str, Any] = {"preview": True}
100
+
101
+ if space_rid:
102
+ list_params["space_rid"] = space_rid
103
+ if page_size:
104
+ list_params["page_size"] = page_size
105
+ if page_token:
106
+ list_params["page_token"] = page_token
107
+
108
+ # The list method returns an iterator
109
+ for project in self.service.Project.list(**list_params):
110
+ projects.append(self._format_project_info(project))
111
+ return projects
112
+ except Exception as e:
113
+ raise RuntimeError(f"Failed to list projects: {e}")
114
+
115
+ def delete_project(self, project_rid: str) -> None:
116
+ """
117
+ Delete a project.
118
+
119
+ Args:
120
+ project_rid: Project Resource Identifier
121
+
122
+ Raises:
123
+ RuntimeError: If deletion fails
124
+ """
125
+ try:
126
+ self.service.Project.delete(project_rid, preview=True)
127
+ except Exception as e:
128
+ raise RuntimeError(f"Failed to delete project {project_rid}: {e}")
129
+
130
+ def update_project(
131
+ self,
132
+ project_rid: str,
133
+ display_name: Optional[str] = None,
134
+ description: Optional[str] = None,
135
+ ) -> Dict[str, Any]:
136
+ """
137
+ Update project information.
138
+
139
+ Args:
140
+ project_rid: Project Resource Identifier
141
+ display_name: New display name (optional)
142
+ description: New description (optional)
143
+
144
+ Returns:
145
+ Updated project information
146
+ """
147
+ update_request: Dict[str, Any] = {}
148
+ if display_name:
149
+ update_request["display_name"] = display_name
150
+ if description:
151
+ update_request["description"] = description
152
+
153
+ if not update_request:
154
+ raise ValueError("At least one field must be provided for update")
155
+
156
+ try:
157
+ project = self.service.Project.update(
158
+ project_rid=project_rid,
159
+ body=update_request,
160
+ preview=True,
161
+ )
162
+ return self._format_project_info(project)
163
+ except Exception as e:
164
+ raise RuntimeError(f"Failed to update project {project_rid}: {e}")
165
+
166
+ def get_projects_batch(self, project_rids: List[str]) -> List[Dict[str, Any]]:
167
+ """
168
+ Get multiple projects in a single request.
169
+
170
+ Args:
171
+ project_rids: List of project RIDs (max 1000)
172
+
173
+ Returns:
174
+ List of project information dictionaries
175
+ """
176
+ if len(project_rids) > 1000:
177
+ raise ValueError("Maximum batch size is 1000 projects")
178
+
179
+ try:
180
+ response = self.service.Project.get_batch(body=project_rids, preview=True)
181
+ projects = []
182
+ for project in response.projects:
183
+ projects.append(self._format_project_info(project))
184
+ return projects
185
+ except Exception as e:
186
+ raise RuntimeError(f"Failed to get projects batch: {e}")
187
+
188
+ def _format_project_info(self, project: Any) -> Dict[str, Any]:
189
+ """
190
+ Format project information for consistent output.
191
+
192
+ Args:
193
+ project: Project object from Foundry SDK
194
+
195
+ Returns:
196
+ Formatted project information dictionary
197
+ """
198
+ return {
199
+ "rid": getattr(project, "rid", None),
200
+ "display_name": getattr(project, "display_name", None),
201
+ "description": getattr(project, "description", None),
202
+ "path": getattr(project, "path", None),
203
+ "space_rid": getattr(project, "space_rid", None),
204
+ "created_by": getattr(project, "created_by", None),
205
+ "created_time": self._format_timestamp(
206
+ getattr(project, "created_time", None)
207
+ ),
208
+ "modified_by": getattr(project, "modified_by", None),
209
+ "modified_time": self._format_timestamp(
210
+ getattr(project, "modified_time", None)
211
+ ),
212
+ "trash_status": getattr(project, "trash_status", None),
213
+ "type": "project",
214
+ }
215
+
216
+ def _format_timestamp(self, timestamp: Any) -> Optional[str]:
217
+ """
218
+ Format timestamp for display.
219
+
220
+ Args:
221
+ timestamp: Timestamp object from SDK
222
+
223
+ Returns:
224
+ Formatted timestamp string or None
225
+ """
226
+ if timestamp is None:
227
+ return None
228
+
229
+ # Handle different timestamp formats from the SDK
230
+ if hasattr(timestamp, "time"):
231
+ return str(timestamp.time)
232
+ return str(timestamp)