collibra-connector 1.0.10b0__tar.gz → 1.0.11__tar.gz

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 (28) hide show
  1. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/PKG-INFO +1 -1
  2. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/collibra_connector/api/Asset.py +198 -20
  3. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/collibra_connector/api/Base.py +2 -1
  4. collibra_connector-1.0.11/collibra_connector/api/Community.py +292 -0
  5. collibra_connector-1.0.11/collibra_connector/api/Domain.py +311 -0
  6. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/collibra_connector/api/Metadata.py +2 -2
  7. collibra_connector-1.0.11/collibra_connector/api/OutputModule.py +48 -0
  8. collibra_connector-1.0.11/collibra_connector/api/Relation.py +206 -0
  9. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/collibra_connector/api/Responsibility.py +19 -0
  10. collibra_connector-1.0.11/collibra_connector/api/Utils.py +103 -0
  11. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/collibra_connector/api/__init__.py +8 -5
  12. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/collibra_connector/connector.py +3 -1
  13. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/collibra_connector.egg-info/PKG-INFO +1 -1
  14. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/collibra_connector.egg-info/SOURCES.txt +3 -0
  15. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/pyproject.toml +1 -1
  16. collibra_connector-1.0.10b0/collibra_connector/api/Community.py +0 -112
  17. collibra_connector-1.0.10b0/collibra_connector/api/Domain.py +0 -116
  18. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/LICENSE +0 -0
  19. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/README.md +0 -0
  20. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/collibra_connector/__init__.py +0 -0
  21. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/collibra_connector/api/Comment.py +0 -0
  22. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/collibra_connector/api/Exceptions.py +0 -0
  23. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/collibra_connector/api/User.py +0 -0
  24. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/collibra_connector/api/Workflow.py +0 -0
  25. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/collibra_connector.egg-info/dependency_links.txt +0 -0
  26. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/collibra_connector.egg-info/requires.txt +0 -0
  27. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/collibra_connector.egg-info/top_level.txt +0 -0
  28. {collibra_connector-1.0.10b0 → collibra_connector-1.0.11}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: collibra-connector
3
- Version: 1.0.10b0
3
+ Version: 1.0.11
4
4
  Summary: An UNOFFICIAL standard Python connector for the Collibra Data Governance Center API.
5
5
  Author-email: Raül Dalgamonni <rauldalgamonnialonso@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/rauldaal/collibra-python-connector
@@ -86,7 +86,7 @@ class Asset(BaseAPI):
86
86
  response = self._post(url=self.__base_api, data=data)
87
87
  return self._handle_response(response)
88
88
 
89
- def update_asset_properties(
89
+ def change_asset(
90
90
  self,
91
91
  asset_id: str,
92
92
  name: str = None,
@@ -146,16 +146,7 @@ class Asset(BaseAPI):
146
146
  "typePublicId": type_public_id,
147
147
  }
148
148
 
149
- # Use PATCH method through requests directly since BaseAPI doesn't have _patch
150
- import requests
151
- response = requests.patch(
152
- f"{self.__base_api}/{asset_id}",
153
- auth=self.__connector.auth,
154
- json=data,
155
- headers=self.__header,
156
- timeout=30
157
- )
158
-
149
+ response = self._patch(url=f"{self.__base_api}/{asset_id}", data=data)
159
150
  return self._handle_response(response)
160
151
 
161
152
  def update_asset_attribute(self, asset_id: str, attribute_id: str, value):
@@ -182,16 +173,203 @@ class Asset(BaseAPI):
182
173
  "typeId": attribute_id
183
174
  }
184
175
 
185
- # Use PUT method through requests directly since BaseAPI doesn't have _put
186
- import requests
187
- response = requests.put(
188
- f"{self.__base_api}/{asset_id}/attributes",
189
- auth=self.__connector.auth,
190
- json=data,
191
- headers=self.__header,
192
- timeout=30
193
- )
176
+ response = self._put(url=f"{self.__base_api}/{asset_id}/attributes", data=data)
177
+ return self._handle_response(response)
178
+
179
+ def set_asset_attributes(self, asset_id: str, type_id: str = None, type_public_id: str = None, values: list = None):
180
+ """
181
+ Set asset attributes. Replaces all attributes of the asset with the given ID
182
+ (of given attribute type) with the attributes from the request.
183
+ :param asset_id: The ID of the asset.
184
+ :param type_id: The ID of the attribute type for the new attribute.
185
+ :param type_public_id: The public ID of the attribute type for the new attribute.
186
+ :param values: The values for the new attribute (list of objects).
187
+ :return: The response from setting the attributes.
188
+ """
189
+ if not asset_id:
190
+ raise ValueError("asset_id is required")
191
+ if not isinstance(asset_id, str):
192
+ raise ValueError("asset_id must be a string")
193
+
194
+ try:
195
+ uuid.UUID(asset_id)
196
+ except ValueError as exc:
197
+ raise ValueError("asset_id must be a valid UUID") from exc
198
+
199
+ if not values:
200
+ raise ValueError("values is required")
201
+ if not isinstance(values, list):
202
+ raise ValueError("values must be a list")
203
+
204
+ # Validate that either type_id or type_public_id is provided
205
+ if not type_id and not type_public_id:
206
+ raise ValueError("Either type_id or type_public_id must be provided")
207
+
208
+ # Validate type_id if provided
209
+ if type_id:
210
+ if not isinstance(type_id, str):
211
+ raise ValueError("type_id must be a string")
212
+ try:
213
+ uuid.UUID(type_id)
214
+ except ValueError as exc:
215
+ raise ValueError("type_id must be a valid UUID") from exc
216
+
217
+ # Validate type_public_id if provided
218
+ if type_public_id and not isinstance(type_public_id, str):
219
+ raise ValueError("type_public_id must be a string")
220
+
221
+ data = {
222
+ "values": values
223
+ }
224
+
225
+ # Add type_id or type_public_id to the data
226
+ if type_id:
227
+ data["typeId"] = type_id
228
+ if type_public_id:
229
+ data["typePublicId"] = type_public_id
230
+
231
+ response = self._put(url=f"{self.__base_api}/{asset_id}/attributes", data=data)
232
+ return self._handle_response(response)
233
+
234
+ def remove_asset(self, asset_id: str):
235
+ """
236
+ Remove an asset identified by given ID.
237
+ :param asset_id: The ID of the asset to remove.
238
+ :return: The response from removing the asset.
239
+ """
240
+ if not asset_id:
241
+ raise ValueError("asset_id is required")
242
+ if not isinstance(asset_id, str):
243
+ raise ValueError("asset_id must be a string")
244
+
245
+ try:
246
+ uuid.UUID(asset_id)
247
+ except ValueError as exc:
248
+ raise ValueError("asset_id must be a valid UUID") from exc
249
+
250
+ response = self._delete(url=f"{self.__base_api}/{asset_id}")
251
+ return self._handle_response(response)
252
+
253
+ def set_asset_relations(self, asset_id: str, related_asset_ids: list, relation_direction: str,
254
+ type_id: str = None, type_public_id: str = None):
255
+ """
256
+ Set relations for the asset with the given ID. All relations described by this request
257
+ will replace the existing ones (identified with asset as one end, relation type and direction).
258
+ :param asset_id: The ID of the asset.
259
+ :param related_asset_ids: The IDs of the related assets (list of UUIDs).
260
+ :param relation_direction: The relation direction ('TO_TARGET' or 'TO_SOURCE').
261
+ :param type_id: The ID of the relation type for the relations to be set.
262
+ :param type_public_id: The public ID of the relation type for the relations to be set.
263
+ :return: The response from setting the relations.
264
+ """
265
+ if not asset_id:
266
+ raise ValueError("asset_id is required")
267
+ if not isinstance(asset_id, str):
268
+ raise ValueError("asset_id must be a string")
269
+
270
+ try:
271
+ uuid.UUID(asset_id)
272
+ except ValueError as exc:
273
+ raise ValueError("asset_id must be a valid UUID") from exc
274
+
275
+ if not related_asset_ids:
276
+ raise ValueError("related_asset_ids is required")
277
+ if not isinstance(related_asset_ids, list):
278
+ raise ValueError("related_asset_ids must be a list")
279
+
280
+ # Validate all related asset IDs are valid UUIDs
281
+ for i, related_id in enumerate(related_asset_ids):
282
+ if not isinstance(related_id, str):
283
+ raise ValueError(f"related_asset_ids[{i}] must be a string")
284
+ try:
285
+ uuid.UUID(related_id)
286
+ except ValueError as exc:
287
+ raise ValueError(f"related_asset_ids[{i}] must be a valid UUID") from exc
288
+
289
+ if not relation_direction:
290
+ raise ValueError("relation_direction is required")
291
+ if relation_direction not in ["TO_TARGET", "TO_SOURCE"]:
292
+ raise ValueError("relation_direction must be either 'TO_TARGET' or 'TO_SOURCE'")
293
+
294
+ # Validate that either type_id or type_public_id is provided
295
+ if not type_id and not type_public_id:
296
+ raise ValueError("Either type_id or type_public_id must be provided")
297
+
298
+ # Validate type_id if provided
299
+ if type_id:
300
+ if not isinstance(type_id, str):
301
+ raise ValueError("type_id must be a string")
302
+ try:
303
+ uuid.UUID(type_id)
304
+ except ValueError as exc:
305
+ raise ValueError("type_id must be a valid UUID") from exc
306
+
307
+ # Validate type_public_id if provided
308
+ if type_public_id and not isinstance(type_public_id, str):
309
+ raise ValueError("type_public_id must be a string")
310
+
311
+ data = {
312
+ "relatedAssetIds": related_asset_ids,
313
+ "relationDirection": relation_direction
314
+ }
315
+
316
+ # Add type_id or type_public_id to the data
317
+ if type_id:
318
+ data["typeId"] = type_id
319
+ if type_public_id:
320
+ data["typePublicId"] = type_public_id
321
+
322
+ response = self._put(url=f"{self.__base_api}/{asset_id}/relations", data=data)
323
+ return self._handle_response(response)
324
+
325
+ def set_asset_responsibilities(self, asset_id: str, role_id: str, owner_ids: list):
326
+ """
327
+ Set responsibilities for the asset with the given ID.
328
+ :param asset_id: The ID of the asset.
329
+ :param role_id: The ID of the role for the responsibilities to be set.
330
+ :param owner_ids: The IDs of the owners (list of UUIDs). An owner is either user or group.
331
+ :return: The response from setting the responsibilities.
332
+ """
333
+ if not asset_id:
334
+ raise ValueError("asset_id is required")
335
+ if not isinstance(asset_id, str):
336
+ raise ValueError("asset_id must be a string")
337
+
338
+ try:
339
+ uuid.UUID(asset_id)
340
+ except ValueError as exc:
341
+ raise ValueError("asset_id must be a valid UUID") from exc
342
+
343
+ if not role_id:
344
+ raise ValueError("role_id is required")
345
+ if not isinstance(role_id, str):
346
+ raise ValueError("role_id must be a string")
347
+
348
+ try:
349
+ uuid.UUID(role_id)
350
+ except ValueError as exc:
351
+ raise ValueError("role_id must be a valid UUID") from exc
352
+
353
+ if not owner_ids:
354
+ raise ValueError("owner_ids is required")
355
+ if not isinstance(owner_ids, list):
356
+ raise ValueError("owner_ids must be a list")
357
+
358
+ # Validate all owner IDs are valid UUIDs
359
+ for i, owner_id in enumerate(owner_ids):
360
+ if not isinstance(owner_id, str):
361
+ raise ValueError(f"owner_ids[{i}] must be a string")
362
+ try:
363
+ uuid.UUID(owner_id)
364
+ except ValueError as exc:
365
+ raise ValueError(f"owner_ids[{i}] must be a valid UUID") from exc
366
+
367
+ data = {
368
+ "roleId": role_id,
369
+ "ownerIds": owner_ids
370
+ }
194
371
 
372
+ response = self._put(url=f"{self.__base_api}/{asset_id}/responsibilities", data=data)
195
373
  return self._handle_response(response)
196
374
 
197
375
  def find_assets(
@@ -38,7 +38,7 @@ class BaseAPI:
38
38
  timeout=self.__connector.timeout
39
39
  )
40
40
 
41
- def _post(self, url: str, data: dict, headers: dict = None):
41
+ def _post(self, url: str, data: dict, headers: dict = None, params: dict = None):
42
42
  """
43
43
  Makes a POST request to the specified URL with the given data.
44
44
  :param url: The URL to send the POST request to.
@@ -56,6 +56,7 @@ class BaseAPI:
56
56
  auth=self.__connector.auth,
57
57
  json=data,
58
58
  headers=headers,
59
+ params=params,
59
60
  timeout=self.__connector.timeout
60
61
  )
61
62
 
@@ -0,0 +1,292 @@
1
+ import uuid
2
+ from .Base import BaseAPI
3
+
4
+
5
+ class Community(BaseAPI):
6
+ def __init__(self, connector):
7
+ super().__init__(connector)
8
+ self.__base_api = connector.api + "/communities"
9
+
10
+ def get_community(self, community_id: str):
11
+ """
12
+ Get a community by its ID.
13
+ :param community_id: The ID of the community to retrieve.
14
+ :return: Community details.
15
+ """
16
+ if not community_id:
17
+ raise ValueError("community_id is required")
18
+ if not isinstance(community_id, str):
19
+ raise ValueError("community_id must be a string")
20
+
21
+ try:
22
+ uuid.UUID(community_id)
23
+ except ValueError as exc:
24
+ raise ValueError("community_id must be a valid UUID") from exc
25
+
26
+ response = self._get(url=f"{self.__base_api}/{community_id}")
27
+ return self._handle_response(response)
28
+
29
+ def find_communities(
30
+ self,
31
+ sort_field: str = "NAME",
32
+ count_limit: int = -1,
33
+ cursor: str = None,
34
+ exclude_meta: bool = True,
35
+ limit: int = 0,
36
+ name: str = None,
37
+ name_match_mode: str = "ANYWHERE",
38
+ offset: int = 0,
39
+ parent_id: str = None,
40
+ sort_order: str = "ASC"
41
+ ):
42
+ """
43
+ Find communities matching the given search criteria.
44
+ :param sort_field: Field to sort results by. Options: NAME, CREATED_BY, CREATED_ON, LAST_MODIFIED, ID
45
+ :param count_limit: Limit elements counted. -1 counts all, 0 skips count. Ignored with cursor pagination.
46
+ :param cursor: Cursor for pagination. Pass empty string for first page, use nextCursor for subsequent pages.
47
+ :param exclude_meta: Whether to exclude meta communities (not manually created by users).
48
+ :param limit: Maximum results to retrieve. 0 uses default, max 1000.
49
+ :param name: Name of community to search for.
50
+ :param name_match_mode: Name matching mode. Options: START, END, ANYWHERE, EXACT
51
+ :param offset: First result to retrieve (deprecated, use cursor instead).
52
+ :param parent_id: Parent community ID to filter by.
53
+ :param sort_order: Sort order. Options: ASC, DESC
54
+ :return: List of communities matching criteria.
55
+ """
56
+ # Validate sort_field
57
+ valid_sort_fields = ["NAME", "CREATED_BY", "CREATED_ON", "LAST_MODIFIED", "ID"]
58
+ if sort_field not in valid_sort_fields:
59
+ raise ValueError(f"sort_field must be one of: {', '.join(valid_sort_fields)}")
60
+
61
+ # Validate name_match_mode
62
+ valid_match_modes = ["START", "END", "ANYWHERE", "EXACT"]
63
+ if name_match_mode not in valid_match_modes:
64
+ raise ValueError(f"name_match_mode must be one of: {', '.join(valid_match_modes)}")
65
+
66
+ # Validate sort_order
67
+ if sort_order not in ["ASC", "DESC"]:
68
+ raise ValueError("sort_order must be 'ASC' or 'DESC'")
69
+
70
+ # Validate limit
71
+ if limit < 0 or limit > 1000:
72
+ raise ValueError("limit must be between 0 and 1000")
73
+
74
+ # Validate parent_id if provided
75
+ if parent_id is not None:
76
+ if not isinstance(parent_id, str):
77
+ raise ValueError("parent_id must be a string")
78
+ try:
79
+ uuid.UUID(parent_id)
80
+ except ValueError as exc:
81
+ raise ValueError("parent_id must be a valid UUID") from exc
82
+
83
+ # Validate cursor and offset usage
84
+ if cursor is not None and offset != 0:
85
+ raise ValueError("Cannot use both cursor and offset in the same request")
86
+
87
+ # Build parameters - only include non-default values
88
+ params = {}
89
+
90
+ if sort_field != "NAME":
91
+ params["sortField"] = sort_field
92
+ if count_limit != -1:
93
+ params["countLimit"] = count_limit
94
+ if cursor is not None:
95
+ params["cursor"] = cursor
96
+ if exclude_meta is not True:
97
+ params["excludeMeta"] = exclude_meta
98
+ if limit != 0:
99
+ params["limit"] = limit
100
+ if name is not None:
101
+ params["name"] = name
102
+ if name_match_mode != "ANYWHERE":
103
+ params["nameMatchMode"] = name_match_mode
104
+ if offset != 0:
105
+ params["offset"] = offset
106
+ if parent_id is not None:
107
+ params["parentId"] = parent_id
108
+ if sort_order != "ASC":
109
+ params["sortOrder"] = sort_order
110
+
111
+ response = self._get(params=params)
112
+ return self._handle_response(response)
113
+
114
+ def add_community(
115
+ self,
116
+ name: str,
117
+ parent_id: str = None,
118
+ description: str = None,
119
+ community_id: str = None
120
+ ):
121
+ """
122
+ Adds a new community with the given parameters.
123
+ :param name: The name of the new community. Should be unique across all communities
124
+ (required, 1-255 characters).
125
+ :param parent_id: The ID of the parent for the new community (optional UUID).
126
+ :param description: The description of the new community (optional).
127
+ :param community_id: The ID of the new community. Should be unique within all communities
128
+ (optional UUID).
129
+ :return: Details of the created community.
130
+ """
131
+ # Validate required parameters
132
+ if not name:
133
+ raise ValueError("name is required")
134
+ if not isinstance(name, str):
135
+ raise ValueError("name must be a string")
136
+ if len(name.strip()) < 1 or len(name) > 255:
137
+ raise ValueError("name must be between 1 and 255 characters")
138
+
139
+ # Validate parent_id if provided
140
+ if parent_id is not None:
141
+ if not isinstance(parent_id, str):
142
+ raise ValueError("parent_id must be a string")
143
+ try:
144
+ uuid.UUID(parent_id)
145
+ except ValueError as exc:
146
+ raise ValueError("parent_id must be a valid UUID") from exc
147
+
148
+ # Validate description if provided
149
+ if description is not None and not isinstance(description, str):
150
+ raise ValueError("description must be a string")
151
+
152
+ # Validate community_id if provided
153
+ if community_id is not None:
154
+ if not isinstance(community_id, str):
155
+ raise ValueError("community_id must be a string")
156
+ try:
157
+ parsed_uuid = uuid.UUID(community_id)
158
+ # Check if UUID starts with reserved prefix
159
+ if str(parsed_uuid).startswith("00000000-0000-0000-"):
160
+ raise ValueError("community_id cannot start with reserved prefix '00000000-0000-0000-'")
161
+ except ValueError as exc:
162
+ if "reserved prefix" in str(exc):
163
+ raise exc
164
+ raise ValueError("community_id must be a valid UUID") from exc
165
+
166
+ # Build request body - only include provided values
167
+ data = {"name": name.strip()}
168
+
169
+ if parent_id is not None:
170
+ data["parentId"] = parent_id
171
+ if description is not None:
172
+ data["description"] = description
173
+ if community_id is not None:
174
+ data["id"] = community_id
175
+
176
+ response = self._post(url=self.__base_api, data=data)
177
+ return self._handle_response(response)
178
+
179
+ def change_community(
180
+ self,
181
+ community_id: str,
182
+ name: str = None,
183
+ parent_id: str = None,
184
+ description: str = None,
185
+ remove_scope_overlap_on_move: bool = None
186
+ ):
187
+ """
188
+ Changes the community with the information that is present in the request.
189
+ Only properties that are specified in this request and have non-null values are updated.
190
+ :param community_id: The ID of the community to be changed (required UUID).
191
+ :param name: The new name for the community (optional, 1-255 characters).
192
+ :param parent_id: The ID of the new parent community (optional UUID).
193
+ :param description: The new description for the community (optional).
194
+ :param remove_scope_overlap_on_move: Whether scopes assigned to domain community
195
+ and its children should be removed on move if there
196
+ are any inherited scopes in new parent community.
197
+ :return: Details of the updated community.
198
+ """
199
+ # Validate required parameters
200
+ if not community_id:
201
+ raise ValueError("community_id is required")
202
+ if not isinstance(community_id, str):
203
+ raise ValueError("community_id must be a string")
204
+
205
+ try:
206
+ uuid.UUID(community_id)
207
+ except ValueError as exc:
208
+ raise ValueError("community_id must be a valid UUID") from exc
209
+
210
+ # Validate name if provided
211
+ if name is not None:
212
+ if not isinstance(name, str):
213
+ raise ValueError("name must be a string")
214
+ if len(name.strip()) < 1 or len(name) > 255:
215
+ raise ValueError("name must be between 1 and 255 characters")
216
+
217
+ # Validate parent_id if provided
218
+ if parent_id is not None:
219
+ if not isinstance(parent_id, str):
220
+ raise ValueError("parent_id must be a string")
221
+ try:
222
+ uuid.UUID(parent_id)
223
+ except ValueError as exc:
224
+ raise ValueError("parent_id must be a valid UUID") from exc
225
+
226
+ # Validate description if provided
227
+ if description is not None and not isinstance(description, str):
228
+ raise ValueError("description must be a string")
229
+
230
+ # Validate remove_scope_overlap_on_move if provided
231
+ if remove_scope_overlap_on_move is not None and not isinstance(remove_scope_overlap_on_move, bool):
232
+ raise ValueError("remove_scope_overlap_on_move must be a boolean")
233
+
234
+ # Build request body - only include provided values
235
+ # Include the community_id in the body as required by the API
236
+ data = {"id": community_id}
237
+
238
+ if name is not None:
239
+ data["name"] = name.strip()
240
+ if parent_id is not None:
241
+ data["parentId"] = parent_id
242
+ if description is not None:
243
+ data["description"] = description
244
+ if remove_scope_overlap_on_move is not None:
245
+ data["removeScopeOverlapOnMove"] = remove_scope_overlap_on_move
246
+
247
+ response = self._patch(url=f"{self.__base_api}/{community_id}", data=data)
248
+ return self._handle_response(response)
249
+
250
+ def remove_community(self, community_id: str):
251
+ """
252
+ Remove a community by its ID.
253
+
254
+ **DEPRECATED**: This endpoint will be removed in the future.
255
+ Please use POST /communities/removalJobs instead.
256
+
257
+ :param community_id: The ID of the community to remove (required UUID).
258
+ :return: Response from the removal operation.
259
+ """
260
+ # Validate required parameters
261
+ if not community_id:
262
+ raise ValueError("community_id is required")
263
+ if not isinstance(community_id, str):
264
+ raise ValueError("community_id must be a string")
265
+
266
+ try:
267
+ uuid.UUID(community_id)
268
+ except ValueError as exc:
269
+ raise ValueError("community_id must be a valid UUID") from exc
270
+
271
+ response = self._delete(url=f"{self.__base_api}/{community_id}")
272
+ return self._handle_response(response)
273
+
274
+ def change_to_root_community(self, community_id: str):
275
+ """
276
+ Changes the community with given ID to a root community.
277
+ :param community_id: The ID of the community that will be changed to a root community (required UUID).
278
+ :return: Details of the updated community.
279
+ """
280
+ # Validate required parameters
281
+ if not community_id:
282
+ raise ValueError("community_id is required")
283
+ if not isinstance(community_id, str):
284
+ raise ValueError("community_id must be a string")
285
+
286
+ try:
287
+ uuid.UUID(community_id)
288
+ except ValueError as exc:
289
+ raise ValueError("community_id must be a valid UUID") from exc
290
+
291
+ response = self._post(url=f"{self.__base_api}/{community_id}/root", data={})
292
+ return self._handle_response(response)