pltr-cli 0.5.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,321 @@
1
+ """
2
+ Resource Role 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 ResourceRoleService(BaseService):
11
+ """Service wrapper for Foundry resource role 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 grant_role(
18
+ self,
19
+ resource_rid: str,
20
+ principal_id: str,
21
+ principal_type: str,
22
+ role_name: str,
23
+ ) -> Dict[str, Any]:
24
+ """
25
+ Grant a role to a principal on a resource.
26
+
27
+ Args:
28
+ resource_rid: Resource Identifier
29
+ principal_id: Principal (user/group) identifier
30
+ principal_type: Principal type ('User' or 'Group')
31
+ role_name: Role name to grant
32
+
33
+ Returns:
34
+ Role grant information
35
+ """
36
+ try:
37
+ role_grant: Dict[str, Any] = {
38
+ "principal_id": principal_id,
39
+ "principal_type": principal_type,
40
+ "role_name": role_name,
41
+ }
42
+
43
+ result = self.service.ResourceRole.grant(
44
+ resource_rid=resource_rid,
45
+ body=role_grant,
46
+ preview=True,
47
+ )
48
+ return self._format_role_grant(result)
49
+ except Exception as e:
50
+ raise RuntimeError(
51
+ f"Failed to grant role '{role_name}' to {principal_type} '{principal_id}' on resource {resource_rid}: {e}"
52
+ )
53
+
54
+ def revoke_role(
55
+ self,
56
+ resource_rid: str,
57
+ principal_id: str,
58
+ principal_type: str,
59
+ role_name: str,
60
+ ) -> None:
61
+ """
62
+ Revoke a role from a principal on a resource.
63
+
64
+ Args:
65
+ resource_rid: Resource Identifier
66
+ principal_id: Principal (user/group) identifier
67
+ principal_type: Principal type ('User' or 'Group')
68
+ role_name: Role name to revoke
69
+
70
+ Raises:
71
+ RuntimeError: If revocation fails
72
+ """
73
+ try:
74
+ role_revocation: Dict[str, Any] = {
75
+ "principal_id": principal_id,
76
+ "principal_type": principal_type,
77
+ "role_name": role_name,
78
+ }
79
+
80
+ self.service.ResourceRole.revoke(
81
+ resource_rid=resource_rid,
82
+ body=role_revocation,
83
+ preview=True,
84
+ )
85
+ except Exception as e:
86
+ raise RuntimeError(
87
+ f"Failed to revoke role '{role_name}' from {principal_type} '{principal_id}' on resource {resource_rid}: {e}"
88
+ )
89
+
90
+ def list_resource_roles(
91
+ self,
92
+ resource_rid: str,
93
+ principal_type: Optional[str] = None,
94
+ page_size: Optional[int] = None,
95
+ page_token: Optional[str] = None,
96
+ ) -> List[Dict[str, Any]]:
97
+ """
98
+ List all roles granted on a resource.
99
+
100
+ Args:
101
+ resource_rid: Resource Identifier
102
+ principal_type: Filter by principal type ('User' or 'Group', optional)
103
+ page_size: Number of items per page (optional)
104
+ page_token: Pagination token (optional)
105
+
106
+ Returns:
107
+ List of role grant information dictionaries
108
+ """
109
+ try:
110
+ role_grants = []
111
+ list_params: Dict[str, Any] = {"preview": True}
112
+
113
+ if principal_type:
114
+ list_params["principal_type"] = principal_type
115
+ if page_size:
116
+ list_params["page_size"] = page_size
117
+ if page_token:
118
+ list_params["page_token"] = page_token
119
+
120
+ # The list method returns an iterator
121
+ for role_grant in self.service.ResourceRole.list(
122
+ resource_rid, **list_params
123
+ ):
124
+ role_grants.append(self._format_role_grant(role_grant))
125
+ return role_grants
126
+ except Exception as e:
127
+ raise RuntimeError(f"Failed to list roles for resource {resource_rid}: {e}")
128
+
129
+ def get_principal_roles(
130
+ self,
131
+ principal_id: str,
132
+ principal_type: str,
133
+ resource_rid: Optional[str] = None,
134
+ page_size: Optional[int] = None,
135
+ page_token: Optional[str] = None,
136
+ ) -> List[Dict[str, Any]]:
137
+ """
138
+ Get all roles granted to a principal, optionally filtered by resource.
139
+
140
+ Args:
141
+ principal_id: Principal (user/group) identifier
142
+ principal_type: Principal type ('User' or 'Group')
143
+ resource_rid: Filter by resource RID (optional)
144
+ page_size: Number of items per page (optional)
145
+ page_token: Pagination token (optional)
146
+
147
+ Returns:
148
+ List of role grant information dictionaries
149
+ """
150
+ try:
151
+ role_grants = []
152
+ list_params = {
153
+ "principal_id": principal_id,
154
+ "principal_type": principal_type,
155
+ "preview": True,
156
+ }
157
+
158
+ if resource_rid:
159
+ list_params["resource_rid"] = resource_rid
160
+ if page_size:
161
+ list_params["page_size"] = page_size
162
+ if page_token:
163
+ list_params["page_token"] = page_token
164
+
165
+ # The get_principal_roles method returns an iterator
166
+ for role_grant in self.service.ResourceRole.get_principal_roles(
167
+ **list_params
168
+ ):
169
+ role_grants.append(self._format_role_grant(role_grant))
170
+ return role_grants
171
+ except Exception as e:
172
+ raise RuntimeError(
173
+ f"Failed to get roles for {principal_type} '{principal_id}': {e}"
174
+ )
175
+
176
+ def bulk_grant_roles(
177
+ self,
178
+ resource_rid: str,
179
+ role_grants: List[Dict[str, str]],
180
+ ) -> List[Dict[str, Any]]:
181
+ """
182
+ Grant multiple roles in a single request.
183
+
184
+ Args:
185
+ resource_rid: Resource Identifier
186
+ role_grants: List of role grant specifications, each containing:
187
+ - principal_id: Principal identifier
188
+ - principal_type: 'User' or 'Group'
189
+ - role_name: Role name to grant
190
+
191
+ Returns:
192
+ List of granted role information dictionaries
193
+ """
194
+ try:
195
+ result = self.service.ResourceRole.bulk_grant(
196
+ resource_rid=resource_rid,
197
+ body={"role_grants": role_grants},
198
+ preview=True,
199
+ )
200
+
201
+ granted_roles = []
202
+ if hasattr(result, "role_grants"):
203
+ for role_grant in result.role_grants:
204
+ granted_roles.append(self._format_role_grant(role_grant))
205
+
206
+ return granted_roles
207
+ except Exception as e:
208
+ raise RuntimeError(
209
+ f"Failed to bulk grant roles on resource {resource_rid}: {e}"
210
+ )
211
+
212
+ def bulk_revoke_roles(
213
+ self,
214
+ resource_rid: str,
215
+ role_revocations: List[Dict[str, str]],
216
+ ) -> None:
217
+ """
218
+ Revoke multiple roles in a single request.
219
+
220
+ Args:
221
+ resource_rid: Resource Identifier
222
+ role_revocations: List of role revocation specifications, each containing:
223
+ - principal_id: Principal identifier
224
+ - principal_type: 'User' or 'Group'
225
+ - role_name: Role name to revoke
226
+
227
+ Raises:
228
+ RuntimeError: If revocation fails
229
+ """
230
+ try:
231
+ self.service.ResourceRole.bulk_revoke(
232
+ resource_rid=resource_rid,
233
+ body={"role_revocations": role_revocations},
234
+ preview=True,
235
+ )
236
+ except Exception as e:
237
+ raise RuntimeError(
238
+ f"Failed to bulk revoke roles on resource {resource_rid}: {e}"
239
+ )
240
+
241
+ def get_available_roles(self, resource_rid: str) -> List[Dict[str, Any]]:
242
+ """
243
+ Get all available roles for a resource type.
244
+
245
+ Args:
246
+ resource_rid: Resource Identifier
247
+
248
+ Returns:
249
+ List of available role information dictionaries
250
+ """
251
+ try:
252
+ roles = []
253
+ for role in self.service.ResourceRole.get_available_roles(
254
+ resource_rid, preview=True
255
+ ):
256
+ roles.append(self._format_role_info(role))
257
+ return roles
258
+ except Exception as e:
259
+ raise RuntimeError(
260
+ f"Failed to get available roles for resource {resource_rid}: {e}"
261
+ )
262
+
263
+ def _format_role_grant(self, role_grant: Any) -> Dict[str, Any]:
264
+ """
265
+ Format role grant information for consistent output.
266
+
267
+ Args:
268
+ role_grant: Role grant object from Foundry SDK
269
+
270
+ Returns:
271
+ Formatted role grant information dictionary
272
+ """
273
+ return {
274
+ "resource_rid": getattr(role_grant, "resource_rid", None),
275
+ "principal_id": getattr(role_grant, "principal_id", None),
276
+ "principal_type": getattr(role_grant, "principal_type", None),
277
+ "role_name": getattr(role_grant, "role_name", None),
278
+ "granted_by": getattr(role_grant, "granted_by", None),
279
+ "granted_time": self._format_timestamp(
280
+ getattr(role_grant, "granted_time", None)
281
+ ),
282
+ "expires_at": self._format_timestamp(
283
+ getattr(role_grant, "expires_at", None)
284
+ ),
285
+ }
286
+
287
+ def _format_role_info(self, role: Any) -> Dict[str, Any]:
288
+ """
289
+ Format role information for consistent output.
290
+
291
+ Args:
292
+ role: Role object from Foundry SDK
293
+
294
+ Returns:
295
+ Formatted role information dictionary
296
+ """
297
+ return {
298
+ "name": getattr(role, "name", None),
299
+ "display_name": getattr(role, "display_name", None),
300
+ "description": getattr(role, "description", None),
301
+ "permissions": getattr(role, "permissions", []),
302
+ "is_owner_like": getattr(role, "is_owner_like", False),
303
+ }
304
+
305
+ def _format_timestamp(self, timestamp: Any) -> Optional[str]:
306
+ """
307
+ Format timestamp for display.
308
+
309
+ Args:
310
+ timestamp: Timestamp object from SDK
311
+
312
+ Returns:
313
+ Formatted timestamp string or None
314
+ """
315
+ if timestamp is None:
316
+ return None
317
+
318
+ # Handle different timestamp formats from the SDK
319
+ if hasattr(timestamp, "time"):
320
+ return str(timestamp.time)
321
+ return str(timestamp)
pltr/services/space.py ADDED
@@ -0,0 +1,354 @@
1
+ """
2
+ Space 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 SpaceService(BaseService):
11
+ """Service wrapper for Foundry space 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_space(
18
+ self,
19
+ display_name: str,
20
+ organization_rid: str,
21
+ description: Optional[str] = None,
22
+ default_roles: Optional[List[str]] = None,
23
+ role_grants: Optional[List[Dict[str, Any]]] = None,
24
+ ) -> Dict[str, Any]:
25
+ """
26
+ Create a new space.
27
+
28
+ Args:
29
+ display_name: Space display name
30
+ organization_rid: Organization Resource Identifier
31
+ description: Space description (optional)
32
+ default_roles: List of default role names (optional)
33
+ role_grants: List of role grant specifications (optional)
34
+
35
+ Returns:
36
+ Created space information
37
+ """
38
+ try:
39
+ # Prepare the create request payload
40
+ create_request: Dict[str, Any] = {
41
+ "display_name": display_name,
42
+ "organization_rid": organization_rid,
43
+ }
44
+
45
+ if description:
46
+ create_request["description"] = description
47
+ if default_roles:
48
+ create_request["default_roles"] = default_roles
49
+ if role_grants:
50
+ create_request["role_grants"] = role_grants
51
+
52
+ space = self.service.Space.create(
53
+ body=create_request,
54
+ preview=True,
55
+ )
56
+ return self._format_space_info(space)
57
+ except Exception as e:
58
+ raise RuntimeError(f"Failed to create space '{display_name}': {e}")
59
+
60
+ def get_space(self, space_rid: str) -> Dict[str, Any]:
61
+ """
62
+ Get information about a specific space.
63
+
64
+ Args:
65
+ space_rid: Space Resource Identifier
66
+
67
+ Returns:
68
+ Space information dictionary
69
+ """
70
+ try:
71
+ space = self.service.Space.get(space_rid, preview=True)
72
+ return self._format_space_info(space)
73
+ except Exception as e:
74
+ raise RuntimeError(f"Failed to get space {space_rid}: {e}")
75
+
76
+ def list_spaces(
77
+ self,
78
+ organization_rid: Optional[str] = None,
79
+ page_size: Optional[int] = None,
80
+ page_token: Optional[str] = None,
81
+ ) -> List[Dict[str, Any]]:
82
+ """
83
+ List spaces, optionally filtered by organization.
84
+
85
+ Args:
86
+ organization_rid: Organization Resource Identifier to filter by (optional)
87
+ page_size: Number of items per page (optional)
88
+ page_token: Pagination token (optional)
89
+
90
+ Returns:
91
+ List of space information dictionaries
92
+ """
93
+ try:
94
+ spaces = []
95
+ list_params: Dict[str, Any] = {"preview": True}
96
+
97
+ if organization_rid:
98
+ list_params["organization_rid"] = organization_rid
99
+ if page_size:
100
+ list_params["page_size"] = page_size
101
+ if page_token:
102
+ list_params["page_token"] = page_token
103
+
104
+ # The list method returns an iterator
105
+ for space in self.service.Space.list(**list_params):
106
+ spaces.append(self._format_space_info(space))
107
+ return spaces
108
+ except Exception as e:
109
+ raise RuntimeError(f"Failed to list spaces: {e}")
110
+
111
+ def update_space(
112
+ self,
113
+ space_rid: str,
114
+ display_name: Optional[str] = None,
115
+ description: Optional[str] = None,
116
+ ) -> Dict[str, Any]:
117
+ """
118
+ Update space information.
119
+
120
+ Args:
121
+ space_rid: Space Resource Identifier
122
+ display_name: New display name (optional)
123
+ description: New description (optional)
124
+
125
+ Returns:
126
+ Updated space information
127
+ """
128
+ update_request: Dict[str, Any] = {}
129
+ if display_name:
130
+ update_request["display_name"] = display_name
131
+ if description:
132
+ update_request["description"] = description
133
+
134
+ if not update_request:
135
+ raise ValueError("At least one field must be provided for update")
136
+
137
+ try:
138
+ space = self.service.Space.update(
139
+ space_rid=space_rid,
140
+ body=update_request,
141
+ preview=True,
142
+ )
143
+ return self._format_space_info(space)
144
+ except Exception as e:
145
+ raise RuntimeError(f"Failed to update space {space_rid}: {e}")
146
+
147
+ def delete_space(self, space_rid: str) -> None:
148
+ """
149
+ Delete a space.
150
+
151
+ Args:
152
+ space_rid: Space Resource Identifier
153
+
154
+ Raises:
155
+ RuntimeError: If deletion fails
156
+ """
157
+ try:
158
+ self.service.Space.delete(space_rid, preview=True)
159
+ except Exception as e:
160
+ raise RuntimeError(f"Failed to delete space {space_rid}: {e}")
161
+
162
+ def get_spaces_batch(self, space_rids: List[str]) -> List[Dict[str, Any]]:
163
+ """
164
+ Get multiple spaces in a single request.
165
+
166
+ Args:
167
+ space_rids: List of space RIDs (max 1000)
168
+
169
+ Returns:
170
+ List of space information dictionaries
171
+ """
172
+ if len(space_rids) > 1000:
173
+ raise ValueError("Maximum batch size is 1000 spaces")
174
+
175
+ try:
176
+ response = self.service.Space.get_batch(body=space_rids, preview=True)
177
+ spaces = []
178
+ for space in response.spaces:
179
+ spaces.append(self._format_space_info(space))
180
+ return spaces
181
+ except Exception as e:
182
+ raise RuntimeError(f"Failed to get spaces batch: {e}")
183
+
184
+ def get_space_members(
185
+ self,
186
+ space_rid: str,
187
+ principal_type: Optional[str] = None,
188
+ page_size: Optional[int] = None,
189
+ page_token: Optional[str] = None,
190
+ ) -> List[Dict[str, Any]]:
191
+ """
192
+ Get all members (users/groups) of a space.
193
+
194
+ Args:
195
+ space_rid: Space Resource Identifier
196
+ principal_type: Filter by principal type ('User' or 'Group', optional)
197
+ page_size: Number of items per page (optional)
198
+ page_token: Pagination token (optional)
199
+
200
+ Returns:
201
+ List of space member information dictionaries
202
+ """
203
+ try:
204
+ members = []
205
+ list_params: Dict[str, Any] = {"preview": True}
206
+
207
+ if principal_type:
208
+ list_params["principal_type"] = principal_type
209
+ if page_size:
210
+ list_params["page_size"] = page_size
211
+ if page_token:
212
+ list_params["page_token"] = page_token
213
+
214
+ # The get_members method returns an iterator
215
+ for member in self.service.Space.get_members(space_rid, **list_params):
216
+ members.append(self._format_member_info(member))
217
+ return members
218
+ except Exception as e:
219
+ raise RuntimeError(f"Failed to get members for space {space_rid}: {e}")
220
+
221
+ def add_space_member(
222
+ self,
223
+ space_rid: str,
224
+ principal_id: str,
225
+ principal_type: str,
226
+ role_name: str,
227
+ ) -> Dict[str, Any]:
228
+ """
229
+ Add a member to a space with a specific role.
230
+
231
+ Args:
232
+ space_rid: Space Resource Identifier
233
+ principal_id: Principal (user/group) identifier
234
+ principal_type: Principal type ('User' or 'Group')
235
+ role_name: Role name to grant
236
+
237
+ Returns:
238
+ Space member information
239
+ """
240
+ try:
241
+ member_request: Dict[str, Any] = {
242
+ "principal_id": principal_id,
243
+ "principal_type": principal_type,
244
+ "role_name": role_name,
245
+ }
246
+
247
+ result = self.service.Space.add_member(
248
+ space_rid=space_rid,
249
+ body=member_request,
250
+ preview=True,
251
+ )
252
+ return self._format_member_info(result)
253
+ except Exception as e:
254
+ raise RuntimeError(
255
+ f"Failed to add {principal_type} '{principal_id}' to space {space_rid}: {e}"
256
+ )
257
+
258
+ def remove_space_member(
259
+ self,
260
+ space_rid: str,
261
+ principal_id: str,
262
+ principal_type: str,
263
+ ) -> None:
264
+ """
265
+ Remove a member from a space.
266
+
267
+ Args:
268
+ space_rid: Space Resource Identifier
269
+ principal_id: Principal (user/group) identifier
270
+ principal_type: Principal type ('User' or 'Group')
271
+
272
+ Raises:
273
+ RuntimeError: If removal fails
274
+ """
275
+ try:
276
+ member_removal: Dict[str, Any] = {
277
+ "principal_id": principal_id,
278
+ "principal_type": principal_type,
279
+ }
280
+
281
+ self.service.Space.remove_member(
282
+ space_rid=space_rid,
283
+ body=member_removal,
284
+ preview=True,
285
+ )
286
+ except Exception as e:
287
+ raise RuntimeError(
288
+ f"Failed to remove {principal_type} '{principal_id}' from space {space_rid}: {e}"
289
+ )
290
+
291
+ def _format_space_info(self, space: Any) -> Dict[str, Any]:
292
+ """
293
+ Format space information for consistent output.
294
+
295
+ Args:
296
+ space: Space object from Foundry SDK
297
+
298
+ Returns:
299
+ Formatted space information dictionary
300
+ """
301
+ return {
302
+ "rid": getattr(space, "rid", None),
303
+ "display_name": getattr(space, "display_name", None),
304
+ "description": getattr(space, "description", None),
305
+ "organization_rid": getattr(space, "organization_rid", None),
306
+ "root_folder_rid": getattr(space, "root_folder_rid", None),
307
+ "created_by": getattr(space, "created_by", None),
308
+ "created_time": self._format_timestamp(
309
+ getattr(space, "created_time", None)
310
+ ),
311
+ "modified_by": getattr(space, "modified_by", None),
312
+ "modified_time": self._format_timestamp(
313
+ getattr(space, "modified_time", None)
314
+ ),
315
+ "trash_status": getattr(space, "trash_status", None),
316
+ "type": "space",
317
+ }
318
+
319
+ def _format_member_info(self, member: Any) -> Dict[str, Any]:
320
+ """
321
+ Format space member information for consistent output.
322
+
323
+ Args:
324
+ member: Member object from Foundry SDK
325
+
326
+ Returns:
327
+ Formatted member information dictionary
328
+ """
329
+ return {
330
+ "space_rid": getattr(member, "space_rid", None),
331
+ "principal_id": getattr(member, "principal_id", None),
332
+ "principal_type": getattr(member, "principal_type", None),
333
+ "role_name": getattr(member, "role_name", None),
334
+ "added_by": getattr(member, "added_by", None),
335
+ "added_time": self._format_timestamp(getattr(member, "added_time", None)),
336
+ }
337
+
338
+ def _format_timestamp(self, timestamp: Any) -> Optional[str]:
339
+ """
340
+ Format timestamp for display.
341
+
342
+ Args:
343
+ timestamp: Timestamp object from SDK
344
+
345
+ Returns:
346
+ Formatted timestamp string or None
347
+ """
348
+ if timestamp is None:
349
+ return None
350
+
351
+ # Handle different timestamp formats from the SDK
352
+ if hasattr(timestamp, "time"):
353
+ return str(timestamp.time)
354
+ return str(timestamp)