collibra-connector 1.0.9__py3-none-any.whl → 1.0.10a0__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.
@@ -17,21 +17,6 @@ class Asset(BaseAPI):
17
17
  """
18
18
  return super()._get(self.__base_api if not url else url, params, headers)
19
19
 
20
- def _post(self, url: str, data: dict):
21
- """
22
- Makes a POST request to the asset API.
23
- :param url: The URL to send the POST request to.
24
- :param data: The data to send in the POST request.
25
- :return: The response from the POST request.
26
- """
27
- return super()._post(url, data)
28
-
29
- def _handle_response(self, response):
30
- return super()._handle_response(response)
31
-
32
- def _uuid_validation(self, id):
33
- return super()._uuid_validation(id)
34
-
35
20
  def get_asset(self, asset_id):
36
21
  """
37
22
  Retrieves an asset by its ID.
@@ -47,7 +32,7 @@ class Asset(BaseAPI):
47
32
  domain_id: str,
48
33
  display_name: str = None,
49
34
  type_id: str = None,
50
- id: str = None,
35
+ _id: str = None,
51
36
  status_id: str = None,
52
37
  excluded_from_auto_hyperlink: bool = False,
53
38
  type_public_id: str = None,
@@ -71,15 +56,15 @@ class Asset(BaseAPI):
71
56
  raise ValueError("excluded_from_auto_hyperlink must be a boolean value.")
72
57
  if type_id and not isinstance(type_id, str):
73
58
  raise ValueError("type_id must be a string if provided.")
74
- if id and not isinstance(id, str):
75
- raise ValueError("id must be a string if provided.")
59
+ if _id and not isinstance(_id, str):
60
+ raise ValueError("_id must be a string if provided.")
76
61
  if status_id and not isinstance(status_id, str):
77
62
  raise ValueError("status_id must be a string if provided.")
78
63
  if type_public_id and not isinstance(type_public_id, str):
79
64
  raise ValueError("type_public_id must be a string if provided.")
80
65
 
81
66
  # Check Ids are UUIDS
82
- if id and self._uuid_validation(id) is False:
67
+ if _id and self._uuid_validation(_id) is False:
83
68
  raise ValueError("id must be a valid UUID.")
84
69
  if domain_id and self._uuid_validation(domain_id) is False:
85
70
  raise ValueError("domain_id must be a valid UUID.")
@@ -100,3 +85,188 @@ class Asset(BaseAPI):
100
85
  }
101
86
  response = self._post(url=self.__base_api, data=data)
102
87
  return self._handle_response(response)
88
+
89
+ def update_asset_properties(
90
+ self,
91
+ asset_id: str,
92
+ name: str = None,
93
+ display_name: str = None,
94
+ type_id: str = None,
95
+ status_id: str = None,
96
+ domain_id: str = None,
97
+ excluded_from_auto_hyperlinking: bool = None,
98
+ type_public_id: str = None
99
+ ):
100
+ """
101
+ Update asset properties.
102
+ :param asset_id: The ID of the asset to update.
103
+ :param name: Optional new name for the asset.
104
+ :param display_name: Optional new display name.
105
+ :param type_id: Optional new type ID.
106
+ :param status_id: Optional new status ID.
107
+ :param domain_id: Optional new domain ID.
108
+ :param excluded_from_auto_hyperlinking: Optional auto-hyperlinking setting.
109
+ :param type_public_id: Optional new type public ID.
110
+ :return: Updated asset details.
111
+ """
112
+ if not asset_id:
113
+ raise ValueError("asset_id is required")
114
+ if not isinstance(asset_id, str):
115
+ raise ValueError("asset_id must be a string")
116
+
117
+ try:
118
+ uuid.UUID(asset_id)
119
+ except ValueError as exc:
120
+ raise ValueError("asset_id must be a valid UUID") from exc
121
+
122
+ # Validate UUID fields if provided
123
+ uuid_fields = [
124
+ ("type_id", type_id),
125
+ ("status_id", status_id),
126
+ ("domain_id", domain_id)
127
+ ]
128
+
129
+ for field_name, field_value in uuid_fields:
130
+ if field_value:
131
+ if not isinstance(field_value, str):
132
+ raise ValueError(f"{field_name} must be a string")
133
+ try:
134
+ uuid.UUID(field_value)
135
+ except ValueError as exc:
136
+ raise ValueError(f"{field_name} must be a valid UUID") from exc
137
+
138
+ data = {
139
+ "id": asset_id,
140
+ "name": name,
141
+ "displayName": display_name,
142
+ "typeId": type_id,
143
+ "statusId": status_id,
144
+ "domainId": domain_id,
145
+ "excludedFromAutoHyperlinking": excluded_from_auto_hyperlinking,
146
+ "typePublicId": type_public_id,
147
+ }
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
+
159
+ return self._handle_response(response)
160
+
161
+ def update_asset_attribute(self, asset_id: str, attribute_id: str, value):
162
+ """
163
+ Update an asset attribute.
164
+ :param asset_id: The ID of the asset.
165
+ :param attribute_id: The ID of the attribute type.
166
+ :param value: The new value for the attribute.
167
+ :return: The response from updating the attribute.
168
+ """
169
+ if not all([asset_id, attribute_id]):
170
+ raise ValueError("asset_id and attribute_id are required")
171
+
172
+ for param_name, param_value in [("asset_id", asset_id), ("attribute_id", attribute_id)]:
173
+ if not isinstance(param_value, str):
174
+ raise ValueError(f"{param_name} must be a string")
175
+ try:
176
+ uuid.UUID(param_value)
177
+ except ValueError as exc:
178
+ raise ValueError(f"{param_name} must be a valid UUID") from exc
179
+
180
+ data = {
181
+ "values": [value],
182
+ "typeId": attribute_id
183
+ }
184
+
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
+ )
194
+
195
+ return self._handle_response(response)
196
+
197
+ def find_assets(
198
+ self,
199
+ community_id: str = None,
200
+ asset_type_ids: list = None,
201
+ domain_id: str = None,
202
+ limit: int = 1000
203
+ ):
204
+ """
205
+ Find assets with optional filters.
206
+ :param community_id: Optional community ID to filter by.
207
+ :param asset_type_ids: Optional list of asset type IDs to filter by.
208
+ :param domain_id: Optional domain ID to filter by.
209
+ :param limit: Maximum number of results per page.
210
+ :return: List of assets matching the criteria.
211
+ """
212
+ params = {"limit": limit}
213
+
214
+ if community_id:
215
+ if not isinstance(community_id, str):
216
+ raise ValueError("community_id must be a string")
217
+ try:
218
+ uuid.UUID(community_id)
219
+ except ValueError as exc:
220
+ raise ValueError("community_id must be a valid UUID") from exc
221
+ params["communityId"] = community_id
222
+
223
+ if asset_type_ids:
224
+ if not isinstance(asset_type_ids, list):
225
+ raise ValueError("asset_type_ids must be a list")
226
+ for type_id in asset_type_ids:
227
+ if not isinstance(type_id, str):
228
+ raise ValueError("All asset_type_ids must be strings")
229
+ try:
230
+ uuid.UUID(type_id)
231
+ except ValueError as exc:
232
+ raise ValueError("All asset_type_ids must be valid UUIDs") from exc
233
+ params["typeIds"] = asset_type_ids
234
+
235
+ if domain_id:
236
+ if not isinstance(domain_id, str):
237
+ raise ValueError("domain_id must be a string")
238
+ try:
239
+ uuid.UUID(domain_id)
240
+ except ValueError as exc:
241
+ raise ValueError("domain_id must be a valid UUID") from exc
242
+ params["domainId"] = domain_id
243
+
244
+ response = self._get(params=params)
245
+ return self._handle_response(response)
246
+
247
+ def get_asset_activities(self, asset_id: str, limit: int = 50):
248
+ """
249
+ Get activities for a specific asset.
250
+ :param asset_id: The ID of the asset.
251
+ :param limit: Maximum number of activities to retrieve.
252
+ :return: List of activities for the asset.
253
+ """
254
+ if not asset_id:
255
+ raise ValueError("asset_id is required")
256
+ if not isinstance(asset_id, str):
257
+ raise ValueError("asset_id must be a string")
258
+
259
+ try:
260
+ uuid.UUID(asset_id)
261
+ except ValueError as exc:
262
+ raise ValueError("asset_id must be a valid UUID") from exc
263
+
264
+ params = {
265
+ "contextId": asset_id,
266
+ "resourceTypes": ["Asset"],
267
+ "limit": limit
268
+ }
269
+
270
+ response = self._get(url=f"{self.__base_api}/activities", params=params)
271
+ result = self._handle_response(response)
272
+ return result.get("results", [])
@@ -9,6 +9,7 @@ from .Exceptions import (
9
9
 
10
10
 
11
11
  class BaseAPI:
12
+
12
13
  def __init__(self, connector):
13
14
  self.__connector = connector
14
15
  self.__base_api = connector.api
@@ -33,7 +34,8 @@ class BaseAPI:
33
34
  url,
34
35
  auth=self.__connector.auth,
35
36
  params=params,
36
- headers=headers
37
+ headers=headers,
38
+ timeout=self.__connector.timeout
37
39
  )
38
40
 
39
41
  def _post(self, url: str, data: dict, headers: dict = None):
@@ -53,7 +55,65 @@ class BaseAPI:
53
55
  url,
54
56
  auth=self.__connector.auth,
55
57
  json=data,
56
- headers=headers
58
+ headers=headers,
59
+ timeout=self.__connector.timeout
60
+ )
61
+
62
+ def _put(self, url: str, data: dict, headers: dict = None):
63
+ """
64
+ Makes a PUT request to the specified URL with the given data.
65
+ :param url: The URL to send the PUT request to.
66
+ :param data: The data to send in the PUT request.
67
+ :return: The response from the PUT request.
68
+ """
69
+ url = self.__base_api if not url else url
70
+ headers = self.__header if not headers else headers
71
+ if not isinstance(data, dict):
72
+ raise ValueError("Data must be a dictionary")
73
+ if not data:
74
+ raise ValueError("Data cannot be empty")
75
+ return requests.put(
76
+ url,
77
+ auth=self.__connector.auth,
78
+ json=data,
79
+ headers=headers,
80
+ timeout=self.__connector.timeout
81
+ )
82
+
83
+ def _delete(self, url: str, headers: dict = None):
84
+ """
85
+ Makes a DELETE request to the specified URL.
86
+ :param url: The URL to send the DELETE request to.
87
+ :return: The response from the DELETE request.
88
+ """
89
+ url = self.__base_api if not url else url
90
+ headers = self.__header if not headers else headers
91
+ return requests.delete(
92
+ url,
93
+ auth=self.__connector.auth,
94
+ headers=headers,
95
+ timeout=self.__connector.timeout
96
+ )
97
+
98
+ def _patch(self, url: str, data: dict, headers: dict = None):
99
+ """
100
+ Makes a PATCH request to the specified URL with the given data.
101
+ :param url: The URL to send the PATCH request to.
102
+ :param data: The data to send in the PATCH request.
103
+ :return: The response from the PATCH request.
104
+ """
105
+ url = self.__base_api if not url else url
106
+ headers = self.__header if not headers else headers
107
+ if not isinstance(data, dict):
108
+ raise ValueError("Data must be a dictionary")
109
+ if not data:
110
+ raise ValueError("Data cannot be empty")
111
+ return requests.patch(
112
+ url,
113
+ auth=self.__connector.auth,
114
+ json=data,
115
+ headers=headers,
116
+ timeout=self.__connector.timeout
57
117
  )
58
118
 
59
119
  def _handle_response(self, response):
@@ -62,22 +122,32 @@ class BaseAPI:
62
122
  :param response: The response object from the API request.
63
123
  :return: The JSON content of the response if successful, otherwise raises an error.
64
124
  """
65
- if response.status_code == 200 or response.status_code == 201:
66
- return response.json()
125
+ if response.status_code in [200, 201]:
126
+ # Check if response has content before trying to parse JSON
127
+ if response.text.strip():
128
+ try:
129
+ return response.json()
130
+ except ValueError as e:
131
+ raise ValueError(f"Invalid JSON response: {e}") from e
132
+ return {}
67
133
  elif response.status_code == 401:
68
- raise UnauthorizedError("Unauthorized access - invalid credentials" + response.text)
134
+ raise UnauthorizedError("Unauthorized access - invalid credentials: " + response.text)
69
135
  elif response.status_code == 403:
70
- raise ForbiddenError("Forbidden access - insufficient permissions" + response.text)
136
+ raise ForbiddenError("Forbidden access - insufficient permissions: " + response.text)
71
137
  elif response.status_code == 404:
72
- raise NotFoundError("The specified resource was not found" + response.text)
138
+ raise NotFoundError("The specified resource was not found: " + response.text)
73
139
  elif response.status_code >= 500:
74
- raise ServerError("Internal server error - something went wrong on the server" + response.text)
140
+ raise ServerError("Internal server error - something went wrong on the server: " + response.text)
141
+ else:
142
+ raise Exception(f"Unexpected status code {response.status_code}: {response.text}")
75
143
 
76
144
  def _uuid_validation(self, id: str):
77
145
  """
78
146
  Validates if the provided ID is a valid UUID.
79
147
  :param id: The ID to validate.
80
- :return: True if the ID is a valid UUID, otherwise raises ValueError.
148
+ :return: True if the ID is a valid UUID, False otherwise.
81
149
  """
150
+ if not id or not isinstance(id, str):
151
+ return False
82
152
  pattern = re.compile(r"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$")
83
153
  return bool(pattern.match(id))
@@ -0,0 +1,125 @@
1
+ import uuid
2
+ from .Base import BaseAPI
3
+
4
+
5
+ class Comment(BaseAPI):
6
+ def __init__(self, connector):
7
+ super().__init__(connector)
8
+ self.__base_api = connector.api + "/comments"
9
+
10
+ def add_comment(self, asset_id: str, content: str):
11
+ """
12
+ Add a comment to an asset.
13
+ :param asset_id: The ID of the asset to comment on.
14
+ :param content: The content of the comment.
15
+ :return: The created comment details.
16
+ """
17
+ if not asset_id or not content:
18
+ raise ValueError("asset_id and content are required parameters")
19
+ if not isinstance(asset_id, str) or not isinstance(content, str):
20
+ raise ValueError("asset_id and content must be strings")
21
+
22
+ try:
23
+ uuid.UUID(asset_id)
24
+ except ValueError as exc:
25
+ raise ValueError("asset_id must be a valid UUID") from exc
26
+
27
+ data = {
28
+ "content": content,
29
+ "baseResource": {
30
+ "id": asset_id,
31
+ "resourceType": "Asset"
32
+ },
33
+ }
34
+
35
+ response = self._post(url=self.__base_api, data=data)
36
+ return self._handle_response(response)
37
+
38
+ def find_comments(
39
+ self,
40
+ base_resource_id: str = None,
41
+ count_limit: int = -1,
42
+ limit: int = 0,
43
+ offset: int = 0,
44
+ parent_id: str = None,
45
+ resolved: bool = None,
46
+ root_comment: bool = None,
47
+ sort_order: str = "DESC",
48
+ user_id: str = None,
49
+ user_threads: bool = False
50
+ ):
51
+ """
52
+ Find comments matching the given search criteria.
53
+ :param base_resource_id: The ID of the resource which the searched comments refer to.
54
+ :param count_limit: Limit the number of elements counted. -1 counts everything, 0 skips count.
55
+ :param limit: Maximum number of results to retrieve. 0 uses default, max 1000.
56
+ :param offset: First result to retrieve. 0 starts from beginning.
57
+ :param parent_id: ID of the comment for which reply comments should be searched.
58
+ :param resolved: Whether the searched comments should be resolved.
59
+ :param root_comment: Whether the searched comments should be root comments.
60
+ :param sort_order: Sort order on creation date. 'ASC' or 'DESC'.
61
+ :param user_id: ID of the user to filter comments by.
62
+ :param user_threads: Whether to search for root comments created by or mentioning the user.
63
+ :return: List of comments matching the criteria.
64
+ """
65
+ # Validate base_resource_id if provided
66
+ if base_resource_id is not None:
67
+ if not isinstance(base_resource_id, str):
68
+ raise ValueError("base_resource_id must be a string")
69
+ try:
70
+ uuid.UUID(base_resource_id)
71
+ except ValueError as exc:
72
+ raise ValueError("base_resource_id must be a valid UUID") from exc
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 user_id if provided
84
+ if user_id is not None:
85
+ if not isinstance(user_id, str):
86
+ raise ValueError("user_id must be a string")
87
+ try:
88
+ uuid.UUID(user_id)
89
+ except ValueError as exc:
90
+ raise ValueError("user_id must be a valid UUID") from exc
91
+
92
+ # Validate sort_order
93
+ if sort_order not in ["ASC", "DESC"]:
94
+ raise ValueError("sort_order must be 'ASC' or 'DESC'")
95
+
96
+ # Validate limit
97
+ if limit < 0 or limit > 1000:
98
+ raise ValueError("limit must be between 0 and 1000")
99
+
100
+ # Build parameters - only include non-None values
101
+ params = {}
102
+
103
+ if base_resource_id is not None:
104
+ params["baseResourceId"] = base_resource_id
105
+ if count_limit != -1: # Only add if different from default
106
+ params["countLimit"] = count_limit
107
+ if limit != 0: # Only add if different from default
108
+ params["limit"] = limit
109
+ if offset != 0: # Only add if different from default
110
+ params["offset"] = offset
111
+ if parent_id is not None:
112
+ params["parentId"] = parent_id
113
+ if resolved is not None:
114
+ params["resolved"] = resolved
115
+ if root_comment is not None:
116
+ params["rootComment"] = root_comment
117
+ if sort_order != "DESC": # Only add if different from default
118
+ params["sortOrder"] = sort_order
119
+ if user_id is not None:
120
+ params["userId"] = user_id
121
+ if user_threads is not False: # Only add if different from default
122
+ params["userThreads"] = user_threads
123
+
124
+ response = self._get(params=params)
125
+ return self._handle_response(response)
@@ -0,0 +1,112 @@
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)