harness-platform-sdk 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. harness_platform_sdk/__init__.py +56 -0
  2. harness_platform_sdk/authz/__init__.py +15 -0
  3. harness_platform_sdk/authz/resource_groups.py +274 -0
  4. harness_platform_sdk/authz/role_assignments.py +274 -0
  5. harness_platform_sdk/authz/roles.py +271 -0
  6. harness_platform_sdk/base_model.py +17 -0
  7. harness_platform_sdk/client.py +1540 -0
  8. harness_platform_sdk/config.py +63 -0
  9. harness_platform_sdk/exceptions.py +68 -0
  10. harness_platform_sdk/iacm_api/__init__.py +19 -0
  11. harness_platform_sdk/iacm_api/workspace_approvals.py +293 -0
  12. harness_platform_sdk/iacm_api/workspace_default_pipelines.py +300 -0
  13. harness_platform_sdk/iacm_api/workspace_states.py +205 -0
  14. harness_platform_sdk/iacm_api/workspace_variables.py +341 -0
  15. harness_platform_sdk/iacm_api/workspaces.py +301 -0
  16. harness_platform_sdk/idp_api/__init__.py +15 -0
  17. harness_platform_sdk/idp_api/catalog_custom_properties.py +389 -0
  18. harness_platform_sdk/idp_api/entities.py +332 -0
  19. harness_platform_sdk/idp_api/scores.py +359 -0
  20. harness_platform_sdk/models/authz/__init__.py +23 -0
  21. harness_platform_sdk/models/authz/resource_groups.py +47 -0
  22. harness_platform_sdk/models/authz/role_assignments.py +37 -0
  23. harness_platform_sdk/models/authz/roles.py +43 -0
  24. harness_platform_sdk/models/iacm_api/__init__.py +44 -0
  25. harness_platform_sdk/models/iacm_api/workspace_approvals.py +82 -0
  26. harness_platform_sdk/models/iacm_api/workspace_default_pipelines.py +104 -0
  27. harness_platform_sdk/models/iacm_api/workspace_states.py +37 -0
  28. harness_platform_sdk/models/iacm_api/workspace_variables.py +87 -0
  29. harness_platform_sdk/models/iacm_api/workspaces.py +107 -0
  30. harness_platform_sdk/models/idp_api/__init__.py +31 -0
  31. harness_platform_sdk/models/idp_api/catalog_custom_properties.py +56 -0
  32. harness_platform_sdk/models/idp_api/entities.py +80 -0
  33. harness_platform_sdk/models/idp_api/scores.py +64 -0
  34. harness_platform_sdk/models/ng_api/__init__.py +45 -0
  35. harness_platform_sdk/models/ng_api/connectors.py +44 -0
  36. harness_platform_sdk/models/ng_api/environments_v2.py +49 -0
  37. harness_platform_sdk/models/ng_api/infrastructures.py +63 -0
  38. harness_platform_sdk/models/ng_api/organizations.py +51 -0
  39. harness_platform_sdk/models/ng_api/projects.py +55 -0
  40. harness_platform_sdk/models/ng_api/secrets.py +45 -0
  41. harness_platform_sdk/models/ng_api/service_overrides.py +78 -0
  42. harness_platform_sdk/models/ng_api/services.py +55 -0
  43. harness_platform_sdk/models/ng_api/user_groups.py +61 -0
  44. harness_platform_sdk/models/ng_api/variables.py +53 -0
  45. harness_platform_sdk/models/pipeline_api/__init__.py +20 -0
  46. harness_platform_sdk/models/pipeline_api/input_sets_v0.py +67 -0
  47. harness_platform_sdk/models/pipeline_api/pipelines_v0.py +76 -0
  48. harness_platform_sdk/models/pipeline_api/triggers_v0.py +98 -0
  49. harness_platform_sdk/models/template_api/__init__.py +11 -0
  50. harness_platform_sdk/models/template_api/templates_v0.py +59 -0
  51. harness_platform_sdk/ng_api/__init__.py +29 -0
  52. harness_platform_sdk/ng_api/connectors.py +269 -0
  53. harness_platform_sdk/ng_api/environments_v2.py +314 -0
  54. harness_platform_sdk/ng_api/infrastructures.py +378 -0
  55. harness_platform_sdk/ng_api/organizations.py +269 -0
  56. harness_platform_sdk/ng_api/projects.py +265 -0
  57. harness_platform_sdk/ng_api/secrets.py +285 -0
  58. harness_platform_sdk/ng_api/service_overrides.py +342 -0
  59. harness_platform_sdk/ng_api/services.py +350 -0
  60. harness_platform_sdk/ng_api/user_groups.py +270 -0
  61. harness_platform_sdk/ng_api/variables.py +312 -0
  62. harness_platform_sdk/pagination.py +19 -0
  63. harness_platform_sdk/pipeline_api/__init__.py +15 -0
  64. harness_platform_sdk/pipeline_api/input_sets_v0.py +377 -0
  65. harness_platform_sdk/pipeline_api/pipelines_v0.py +324 -0
  66. harness_platform_sdk/pipeline_api/triggers_v0.py +372 -0
  67. harness_platform_sdk/py.typed +0 -0
  68. harness_platform_sdk/scope.py +28 -0
  69. harness_platform_sdk/template_api/__init__.py +10 -0
  70. harness_platform_sdk/template_api/templates_v0.py +576 -0
  71. harness_platform_sdk-1.0.0.dist-info/METADATA +209 -0
  72. harness_platform_sdk-1.0.0.dist-info/RECORD +74 -0
  73. harness_platform_sdk-1.0.0.dist-info/WHEEL +5 -0
  74. harness_platform_sdk-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,56 @@
1
+ """Harness Platform SDK.
2
+
3
+ A Python SDK for interacting with the Harness Platform API.
4
+ Provides unified access to all Harness APIs (Organizations, Projects,
5
+ Pipelines, Connectors, Secrets, and more) with built-in authentication,
6
+ scope management, pagination, and retry handling.
7
+ """
8
+
9
+ from .authz import *
10
+ from .client import HarnessClient
11
+ from .config import HarnessConfig
12
+ from .exceptions import ApiError, AuthError, HarnessSdkError, ScopeNotSetError
13
+ from .iacm_api import *
14
+ from .idp_api import *
15
+ from .ng_api import *
16
+ from .pipeline_api import *
17
+ from .scope import Scope
18
+ from .template_api import *
19
+
20
+ __version__ = "1.0.0"
21
+
22
+ __all__ = [
23
+ "HarnessClient",
24
+ "HarnessConfig",
25
+ "Scope",
26
+ "HarnessSdkError",
27
+ "ScopeNotSetError",
28
+ "ApiError",
29
+ "AuthError",
30
+ "OrganizationsApi",
31
+ "ProjectsApi",
32
+ "ServicesApi",
33
+ "RolesApi",
34
+ "ResourceGroupsApi",
35
+ "RoleAssignmentsApi",
36
+ "ConnectorsApi",
37
+ "SecretsApi",
38
+ "InfrastructuresApi",
39
+ "UserGroupsApi",
40
+ "PipelinesV0Api",
41
+ "InputSetsV0Api",
42
+ "TriggersV0Api",
43
+ "TemplatesV0Api",
44
+ "VariablesApi",
45
+ "ServiceOverridesApi",
46
+ # Infrastructure as Code
47
+ "WorkspacesApi",
48
+ "WorkspaceApprovalsApi",
49
+ "WorkspaceDefaultPipelinesApi",
50
+ "WorkspaceStatesApi",
51
+ "WorkspaceVariablesApi",
52
+ # Internal Developer Portal
53
+ "CatalogCustomPropertyApi",
54
+ "EntityApi",
55
+ "ScoreApi",
56
+ ]
@@ -0,0 +1,15 @@
1
+ """Harness Authorization API resources.
2
+
3
+ Provides APIs for managing roles, resource groups, and role assignments
4
+ under the /authz/ path root.
5
+ """
6
+
7
+ from .resource_groups import ResourceGroupsApi
8
+ from .role_assignments import RoleAssignmentsApi
9
+ from .roles import RolesApi
10
+
11
+ __all__ = [
12
+ "RolesApi",
13
+ "ResourceGroupsApi",
14
+ "RoleAssignmentsApi",
15
+ ]
@@ -0,0 +1,274 @@
1
+ """ResourceGroups API client for Harness SDK.
2
+
3
+ Provides CRUD operations for resource_group resources.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from collections.abc import Iterator
9
+
10
+ from harness_platform_sdk.client import HarnessClient
11
+ from harness_platform_sdk.models.authz.resource_groups import (
12
+ ResourceGroupCreateRequest,
13
+ ResourceGroupResponse,
14
+ )
15
+ from harness_platform_sdk.pagination import PaginationStyle
16
+ from harness_platform_sdk.scope import Scope
17
+
18
+
19
+ class ResourceGroupsApi:
20
+ """API client for resource_group operations."""
21
+
22
+ def __init__(self, client: HarnessClient) -> None:
23
+ """Initialize ResourceGroupsApi with HarnessClient.
24
+
25
+ Args:
26
+ client: HarnessClient instance for making requests.
27
+ """
28
+ self._client = client
29
+
30
+ @property
31
+ def root_api_path(self) -> str:
32
+ """Get the root API path for resource group endpoints.
33
+
34
+ Returns:
35
+ str: The base API path for resource group operations.
36
+ """
37
+ return "/authz/api/v2/resourcegroup"
38
+
39
+ @property
40
+ def unwrap_key(self) -> str:
41
+ """Get the response unwrap key for resource group data.
42
+
43
+ Returns:
44
+ str: The key used to extract resource group data from API responses.
45
+ """
46
+ return "resourceGroup"
47
+
48
+ @property
49
+ def should_wrap(self) -> bool:
50
+ """Check if request bodies should be wrapped.
51
+
52
+ Returns:
53
+ bool: True if request bodies need to be wrapped before sending to API.
54
+ """
55
+ return True
56
+
57
+ @property
58
+ def default_params(self):
59
+ """Get the Default Request Parameters configuration."""
60
+ return getattr(self, "_default_params", None)
61
+
62
+ @default_params.setter
63
+ def default_params(self, resolved: Scope) -> dict:
64
+ """Resolve Scope Variables and Set Default Params.
65
+
66
+ Args:
67
+ resolved: Scope containing account/org/project context.
68
+ scope: Call-time scope (takes precedence).
69
+
70
+ Returns:
71
+ Dictionary of Parsed Querystrings from the scope
72
+
73
+ Raises:
74
+ ScopeNotSetError: If required fields are missing.
75
+ """
76
+ self._default_params = self._client._build_url(
77
+ "&".join(
78
+ [
79
+ "accountIdentifier={account_id}",
80
+ "orgIdentifier={org}",
81
+ "projectIdentifier={project}",
82
+ ]
83
+ ),
84
+ resolved,
85
+ is_params=True,
86
+ )
87
+
88
+ @property
89
+ def resolved_scope(self):
90
+ """Get the Resolved Scope configuration."""
91
+ return getattr(self, "_resolved_scope", None)
92
+
93
+ @resolved_scope.setter
94
+ def resolved_scope(self, scope: Scope) -> str:
95
+ """Resolve Scope Variables and Set Default Params.
96
+
97
+ Args:
98
+ scope: Call-time scope (takes precedence).
99
+
100
+ Returns:
101
+ Resolved Scope with all required fields.
102
+
103
+ Raises:
104
+ ScopeNotSetError: If required fields are missing.
105
+ """
106
+ self._resolved_scope = self._client._resolve_scope(scope)
107
+ # Call out to configure the default params
108
+ self.default_params = self._resolved_scope
109
+
110
+ def _wrapped_body(self, body: ResourceGroupCreateRequest) -> dict:
111
+ """Resolve and wrap the body payload to additionally inject scope details into the payload."""
112
+ if not self.should_wrap:
113
+ return body
114
+
115
+ body = body.model_dump(exclude_none=True)
116
+
117
+ if "accountIdentifier" not in body or body["accountIdentifier"] is None:
118
+ body["accountIdentifier"] = self.resolved_scope.account_id
119
+ if "orgIdentifier" not in body or body["orgIdentifier"] is None:
120
+ body["orgIdentifier"] = self.resolved_scope.org
121
+ if "projectIdentifier" not in body or body["projectIdentifier"] is None:
122
+ body["projectIdentifier"] = self.resolved_scope.project
123
+
124
+ return {self.unwrap_key: body}
125
+
126
+ def list(self, scope: Scope | None = None, **kwargs) -> Iterator[ResourceGroupResponse]:
127
+ """List resource_groups in the specified organization.
128
+
129
+ Args:
130
+ scope: Scope containing org. If None, uses client default scope.
131
+ **kwargs: Additional query parameters (e.g., searchTerm).
132
+
133
+ Yields:
134
+ ResourceGroupResponse: Individual resource_group items across all pages.
135
+
136
+ Raises:
137
+ ScopeNotSetError: If scope cannot be resolved.
138
+ """
139
+ self.resolved_scope = scope
140
+ kwargs.update(self.default_params)
141
+
142
+ url = self._client._build_url(
143
+ "{root_api_path}",
144
+ self.resolved_scope,
145
+ root_api_path=self.root_api_path,
146
+ )
147
+ return self._client._paginate(
148
+ url,
149
+ params=kwargs,
150
+ response_model=ResourceGroupResponse,
151
+ pagination_style=PaginationStyle.OFFSET, # per pagination_inventory.md
152
+ scope=self.resolved_scope,
153
+ unwrap_field=self.unwrap_key, # API wraps each item in a "self.unwrap_key" field
154
+ )
155
+
156
+ def get(self, identifier: str, scope: Scope | None = None) -> ResourceGroupResponse:
157
+ """Get a single resource_group by ID.
158
+
159
+ Args:
160
+ identifier: ResourceGroup identifier.
161
+ scope: Scope containing resource scope. If None, uses client default scope.
162
+
163
+ Returns:
164
+ ResourceGroupResponse: The requested resource_group.
165
+
166
+ Raises:
167
+ ScopeNotSetError: If scope cannot be resolved.
168
+ ApiError: For non-2xx responses.
169
+ """
170
+ self.resolved_scope = scope
171
+ url = self._client._build_url(
172
+ "{root_api_path}/{identifier}",
173
+ self.resolved_scope,
174
+ root_api_path=self.root_api_path,
175
+ identifier=identifier,
176
+ )
177
+
178
+ response = self._client._get(url, params=self.default_params, response_model=None)
179
+ if not response:
180
+ return {}
181
+
182
+ unwrapped = self._client._unwrap_response(
183
+ key_type=self.unwrap_key, raw_data=response, scope=self.resolved_scope
184
+ )
185
+ return ResourceGroupResponse(**unwrapped)
186
+
187
+ def create(
188
+ self, body: ResourceGroupCreateRequest, scope: Scope | None = None
189
+ ) -> ResourceGroupResponse:
190
+ """Create a new resource_group.
191
+
192
+ Args:
193
+ body: ResourceGroupCreateRequest request with required fields.
194
+ scope: Scope containing resource scope. If None, uses client default scope.
195
+ scope: Scope containing org. If None, uses client default scope.
196
+
197
+ Returns:
198
+ ResourceGroupResponse: The created resource_group.
199
+
200
+ Raises:
201
+ ScopeNotSetError: If scope cannot be resolved.
202
+ ApiError: For non-2xx responses.
203
+ """
204
+ self.resolved_scope = scope
205
+ url = self._client._build_url(
206
+ "{root_api_path}",
207
+ self.resolved_scope,
208
+ root_api_path=self.root_api_path,
209
+ )
210
+
211
+ response = self._client._post(
212
+ url, params=self.default_params, body=self._wrapped_body(body), response_model=None
213
+ )
214
+
215
+ unwrapped = self._client._unwrap_response(key_type=self.unwrap_key, raw_data=response)
216
+ return ResourceGroupResponse(**unwrapped)
217
+
218
+ def update(
219
+ self,
220
+ identifier: str,
221
+ body: ResourceGroupCreateRequest,
222
+ scope: Scope | None = None,
223
+ ) -> ResourceGroupResponse:
224
+ """Update an existing resource_group.
225
+
226
+ Args:
227
+ identifier: resource_group identifier.
228
+ body: ResourceGroupCreateRequest request with updated fields.
229
+ scope: Scope containing resource scope. If None, uses client default scope.
230
+
231
+ Returns:
232
+ ResourceGroupResponse: The updated resource_group.
233
+
234
+ Raises:
235
+ ScopeNotSetError: If scope cannot be resolved.
236
+ ApiError: For non-2xx responses.
237
+ """
238
+ self.resolved_scope = scope
239
+ url = self._client._build_url(
240
+ "{root_api_path}/{identifier}",
241
+ self.resolved_scope,
242
+ root_api_path=self.root_api_path,
243
+ identifier=identifier,
244
+ )
245
+
246
+ response = self._client._put(
247
+ url, params=self.default_params, body=self._wrapped_body(body), response_model=None
248
+ )
249
+
250
+ unwrapped = self._client._unwrap_response(key_type=self.unwrap_key, raw_data=response)
251
+ return ResourceGroupResponse(**unwrapped)
252
+
253
+ def delete(self, identifier: str, scope: Scope | None = None) -> dict | None:
254
+ """Delete a resource_group.
255
+
256
+ Args:
257
+ identifier: resource_group identifier.
258
+ scope: Scope containing resource scope. If None, uses client default scope.
259
+
260
+ Returns:
261
+ dict | None: Response data (typically empty for DELETE).
262
+
263
+ Raises:
264
+ ScopeNotSetError: If scope cannot be resolved.
265
+ ApiError: For non-2xx responses.
266
+ """
267
+ self.resolved_scope = scope
268
+ url = self._client._build_url(
269
+ "{root_api_path}/{identifier}",
270
+ self.resolved_scope,
271
+ root_api_path=self.root_api_path,
272
+ identifier=identifier,
273
+ )
274
+ return self._client._delete(url, params=self.default_params, response_model=None)
@@ -0,0 +1,274 @@
1
+ """RoleAssignments API client for Harness SDK.
2
+
3
+ Provides CRUD operations for role_assignment resources.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from collections.abc import Iterator
9
+
10
+ from harness_platform_sdk.client import HarnessClient
11
+ from harness_platform_sdk.models.authz.role_assignments import (
12
+ RoleAssignmentCreateRequest,
13
+ RoleAssignmentResponse,
14
+ )
15
+ from harness_platform_sdk.pagination import PaginationStyle
16
+ from harness_platform_sdk.scope import Scope
17
+
18
+
19
+ class RoleAssignmentsApi:
20
+ """API client for role_assignment operations."""
21
+
22
+ def __init__(self, client: HarnessClient) -> None:
23
+ """Initialize RoleAssignmentsApi with HarnessClient.
24
+
25
+ Args:
26
+ client: HarnessClient instance for making requests.
27
+ """
28
+ self._client = client
29
+
30
+ @property
31
+ def root_api_path(self) -> str:
32
+ """Get the root API path for role assignment endpoints.
33
+
34
+ Returns:
35
+ str: The base API path for role assignment operations.
36
+ """
37
+ return "/authz/api/roleassignments"
38
+
39
+ @property
40
+ def unwrap_key(self) -> str:
41
+ """Get the response unwrap key for role assignment data.
42
+
43
+ Returns:
44
+ str: The key used to extract role assignment data from API responses.
45
+ """
46
+ return "roleAssignment"
47
+
48
+ @property
49
+ def should_wrap(self) -> bool:
50
+ """Check if request bodies should be wrapped.
51
+
52
+ Returns:
53
+ bool: False, as role assignment request bodies do not need wrapping.
54
+ """
55
+ return False
56
+
57
+ @property
58
+ def default_params(self):
59
+ """Get the Default Request Parameters configuration."""
60
+ return getattr(self, "_default_params", None)
61
+
62
+ @default_params.setter
63
+ def default_params(self, resolved: Scope) -> dict:
64
+ """Resolve Scope Variables and Set Default Params.
65
+
66
+ Args:
67
+ resolved: Scope containing account/org/project context.
68
+ scope: Call-time scope (takes precedence).
69
+
70
+ Returns:
71
+ Dictionary of Parsed Querystrings from the scope
72
+
73
+ Raises:
74
+ ScopeNotSetError: If required fields are missing.
75
+ """
76
+ self._default_params = self._client._build_url(
77
+ "&".join(
78
+ [
79
+ "accountIdentifier={account_id}",
80
+ "orgIdentifier={org}",
81
+ "projectIdentifier={project}",
82
+ ]
83
+ ),
84
+ resolved,
85
+ is_params=True,
86
+ )
87
+
88
+ @property
89
+ def resolved_scope(self):
90
+ """Get the Resolved Scope configuration."""
91
+ return getattr(self, "_resolved_scope", None)
92
+
93
+ @resolved_scope.setter
94
+ def resolved_scope(self, scope: Scope) -> str:
95
+ """Resolve Scope Variables and Set Default Params.
96
+
97
+ Args:
98
+ scope: Call-time scope (takes precedence).
99
+
100
+ Returns:
101
+ Resolved Scope with all required fields.
102
+
103
+ Raises:
104
+ ScopeNotSetError: If required fields are missing.
105
+ """
106
+ self._resolved_scope = self._client._resolve_scope(scope)
107
+ # Call out to configure the default params
108
+ self.default_params = self._resolved_scope
109
+
110
+ def _wrapped_body(self, body: RoleAssignmentCreateRequest) -> dict:
111
+ """Resolve and wrap the body payload to additionally inject scope details into the payload."""
112
+ if not self.should_wrap:
113
+ return body
114
+
115
+ body = body.model_dump(exclude_none=True)
116
+
117
+ if "accountIdentifier" not in body or body["accountIdentifier"] is None:
118
+ body["accountIdentifier"] = self.resolved_scope.account_id
119
+ if "orgIdentifier" not in body or body["orgIdentifier"] is None:
120
+ body["orgIdentifier"] = self.resolved_scope.org
121
+ if "projectIdentifier" not in body or body["projectIdentifier"] is None:
122
+ body["projectIdentifier"] = self.resolved_scope.project
123
+
124
+ return {self.unwrap_key: body}
125
+
126
+ def list(self, scope: Scope | None = None, **kwargs) -> Iterator[RoleAssignmentResponse]:
127
+ """List role_assignments in the specified organization.
128
+
129
+ Args:
130
+ scope: Scope containing org. If None, uses client default scope.
131
+ **kwargs: Additional query parameters (e.g., searchTerm).
132
+
133
+ Yields:
134
+ RoleAssignmentResponse: Individual role_assignment items across all pages.
135
+
136
+ Raises:
137
+ ScopeNotSetError: If scope cannot be resolved.
138
+ """
139
+ self.resolved_scope = scope
140
+ kwargs.update(self.default_params)
141
+
142
+ url = self._client._build_url(
143
+ "{root_api_path}",
144
+ self.resolved_scope,
145
+ root_api_path=self.root_api_path,
146
+ )
147
+ return self._client._paginate(
148
+ url,
149
+ params=kwargs,
150
+ response_model=RoleAssignmentResponse,
151
+ pagination_style=PaginationStyle.OFFSET, # per pagination_inventory.md
152
+ scope=self.resolved_scope,
153
+ unwrap_field=self.unwrap_key, # API wraps each item in a "self.unwrap_key" field
154
+ )
155
+
156
+ def get(self, identifier: str, scope: Scope | None = None) -> RoleAssignmentResponse:
157
+ """Get a single role_assignment by ID.
158
+
159
+ Args:
160
+ identifier: RoleAssignment identifier.
161
+ scope: Scope containing resource scope. If None, uses client default scope.
162
+
163
+ Returns:
164
+ RoleAssignmentResponse: The requested role_assignment.
165
+
166
+ Raises:
167
+ ScopeNotSetError: If scope cannot be resolved.
168
+ ApiError: For non-2xx responses.
169
+ """
170
+ self.resolved_scope = scope
171
+ url = self._client._build_url(
172
+ "{root_api_path}/{identifier}",
173
+ self.resolved_scope,
174
+ root_api_path=self.root_api_path,
175
+ identifier=identifier,
176
+ )
177
+
178
+ response = self._client._get(url, params=self.default_params, response_model=None)
179
+ if not response:
180
+ return {}
181
+
182
+ unwrapped = self._client._unwrap_response(
183
+ key_type=self.unwrap_key, raw_data=response, scope=self.resolved_scope
184
+ )
185
+ return RoleAssignmentResponse(**unwrapped)
186
+
187
+ def create(
188
+ self, body: RoleAssignmentCreateRequest, scope: Scope | None = None
189
+ ) -> RoleAssignmentResponse:
190
+ """Create a new role_assignment.
191
+
192
+ Args:
193
+ body: RoleAssignmentCreateRequest request with required fields.
194
+ scope: Scope containing resource scope. If None, uses client default scope.
195
+ scope: Scope containing org. If None, uses client default scope.
196
+
197
+ Returns:
198
+ RoleAssignmentResponse: The created role_assignment.
199
+
200
+ Raises:
201
+ ScopeNotSetError: If scope cannot be resolved.
202
+ ApiError: For non-2xx responses.
203
+ """
204
+ self.resolved_scope = scope
205
+ url = self._client._build_url(
206
+ "{root_api_path}",
207
+ self.resolved_scope,
208
+ root_api_path=self.root_api_path,
209
+ )
210
+
211
+ response = self._client._post(
212
+ url, params=self.default_params, body=self._wrapped_body(body), response_model=None
213
+ )
214
+
215
+ unwrapped = self._client._unwrap_response(key_type=self.unwrap_key, raw_data=response)
216
+ return RoleAssignmentResponse(**unwrapped)
217
+
218
+ def update(
219
+ self,
220
+ identifier: str,
221
+ body: RoleAssignmentCreateRequest,
222
+ scope: Scope | None = None,
223
+ ) -> RoleAssignmentResponse:
224
+ """Update an existing role_assignment.
225
+
226
+ Args:
227
+ identifier: role_assignment identifier.
228
+ body: RoleAssignmentCreateRequest request with updated fields.
229
+ scope: Scope containing resource scope. If None, uses client default scope.
230
+
231
+ Returns:
232
+ RoleAssignmentResponse: The updated role_assignment.
233
+
234
+ Raises:
235
+ ScopeNotSetError: If scope cannot be resolved.
236
+ ApiError: For non-2xx responses.
237
+ """
238
+ self.resolved_scope = scope
239
+ url = self._client._build_url(
240
+ "{root_api_path}/{identifier}",
241
+ self.resolved_scope,
242
+ root_api_path=self.root_api_path,
243
+ identifier=identifier,
244
+ )
245
+
246
+ response = self._client._put(
247
+ url, params=self.default_params, body=self._wrapped_body(body), response_model=None
248
+ )
249
+
250
+ unwrapped = self._client._unwrap_response(key_type=self.unwrap_key, raw_data=response)
251
+ return RoleAssignmentResponse(**unwrapped)
252
+
253
+ def delete(self, identifier: str, scope: Scope | None = None) -> dict | None:
254
+ """Delete a role_assignment.
255
+
256
+ Args:
257
+ identifier: role_assignment identifier.
258
+ scope: Scope containing resource scope. If None, uses client default scope.
259
+
260
+ Returns:
261
+ dict | None: Response data (typically empty for DELETE).
262
+
263
+ Raises:
264
+ ScopeNotSetError: If scope cannot be resolved.
265
+ ApiError: For non-2xx responses.
266
+ """
267
+ self.resolved_scope = scope
268
+ url = self._client._build_url(
269
+ "{root_api_path}/{identifier}",
270
+ self.resolved_scope,
271
+ root_api_path=self.root_api_path,
272
+ identifier=identifier,
273
+ )
274
+ return self._client._delete(url, params=self.default_params, response_model=None)