collibra-connector 1.0.9__py3-none-any.whl → 1.0.10b0__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,116 @@
1
+ import uuid
2
+ from .Base import BaseAPI
3
+
4
+
5
+ class Domain(BaseAPI):
6
+ def __init__(self, connector):
7
+ super().__init__(connector)
8
+ self.__base_api = connector.api + "/domains"
9
+
10
+ def get_domain(self, domain_id: str):
11
+ """
12
+ Get a domain by its ID.
13
+ :param domain_id: The ID of the domain to retrieve.
14
+ :return: Domain details.
15
+ """
16
+ if not domain_id:
17
+ raise ValueError("domain_id is required")
18
+ if not isinstance(domain_id, str):
19
+ raise ValueError("domain_id must be a string")
20
+
21
+ try:
22
+ uuid.UUID(domain_id)
23
+ except ValueError as exc:
24
+ raise ValueError("domain_id must be a valid UUID") from exc
25
+
26
+ response = self._get(url=f"{self.__base_api}/{domain_id}")
27
+ return self._handle_response(response)
28
+
29
+ def find_domains(
30
+ self,
31
+ community_id: str = None,
32
+ count_limit: int = -1,
33
+ cursor: str = None,
34
+ exclude_meta: bool = True,
35
+ include_sub_communities: bool = False,
36
+ limit: int = 0,
37
+ name: str = None,
38
+ name_match_mode: str = "ANYWHERE",
39
+ offset: int = 0,
40
+ type_id: str = None,
41
+ type_public_id: str = None
42
+ ):
43
+ """
44
+ Find domains matching the given search criteria.
45
+ :param community_id: ID of the community to find domains in.
46
+ :param count_limit: Limit elements counted. -1 counts all, 0 skips count. Ignored with cursor pagination.
47
+ :param cursor: Cursor for pagination. Pass empty string for first page, use nextCursor for subsequent pages.
48
+ :param exclude_meta: Whether to exclude meta domains (not manually created by users).
49
+ :param include_sub_communities: Whether to search in sub-communities of the specified community.
50
+ :param limit: Maximum results to retrieve. 0 uses default, max 1000.
51
+ :param name: Name of domain to search for.
52
+ :param name_match_mode: Name matching mode. Options: START, END, ANYWHERE, EXACT
53
+ :param offset: First result to retrieve (deprecated, use cursor instead).
54
+ :param type_id: Domain type ID to filter by.
55
+ :param type_public_id: Domain type public ID to filter by.
56
+ :return: List of domains matching criteria.
57
+ """
58
+ # Validate name_match_mode
59
+ valid_match_modes = ["START", "END", "ANYWHERE", "EXACT"]
60
+ if name_match_mode not in valid_match_modes:
61
+ raise ValueError(f"name_match_mode must be one of: {', '.join(valid_match_modes)}")
62
+
63
+ # Validate limit
64
+ if limit < 0 or limit > 1000:
65
+ raise ValueError("limit must be between 0 and 1000")
66
+
67
+ # Validate community_id if provided
68
+ if community_id is not None:
69
+ if not isinstance(community_id, str):
70
+ raise ValueError("community_id must be a string")
71
+ try:
72
+ uuid.UUID(community_id)
73
+ except ValueError as exc:
74
+ raise ValueError("community_id must be a valid UUID") from exc
75
+
76
+ # Validate type_id if provided
77
+ if type_id is not None:
78
+ if not isinstance(type_id, str):
79
+ raise ValueError("type_id must be a string")
80
+ try:
81
+ uuid.UUID(type_id)
82
+ except ValueError as exc:
83
+ raise ValueError("type_id must be a valid UUID") from exc
84
+
85
+ # Validate cursor and offset usage
86
+ if cursor is not None and offset != 0:
87
+ raise ValueError("Cannot use both cursor and offset in the same request")
88
+
89
+ # Build parameters - only include non-default values
90
+ params = {}
91
+
92
+ if community_id is not None:
93
+ params["communityId"] = community_id
94
+ if count_limit != -1:
95
+ params["countLimit"] = count_limit
96
+ if cursor is not None:
97
+ params["cursor"] = cursor
98
+ if exclude_meta is not True:
99
+ params["excludeMeta"] = exclude_meta
100
+ if include_sub_communities is not False:
101
+ params["includeSubCommunities"] = include_sub_communities
102
+ if limit != 0:
103
+ params["limit"] = limit
104
+ if name is not None:
105
+ params["name"] = name
106
+ if name_match_mode != "ANYWHERE":
107
+ params["nameMatchMode"] = name_match_mode
108
+ if offset != 0:
109
+ params["offset"] = offset
110
+ if type_id is not None:
111
+ params["typeId"] = type_id
112
+ if type_public_id is not None:
113
+ params["typePublicId"] = type_public_id
114
+
115
+ response = self._get(params=params)
116
+ return self._handle_response(response)
@@ -1,24 +1,19 @@
1
1
 
2
2
  class CollibraAPIError(Exception):
3
3
  """Base exception for Collibra API errors"""
4
- pass
5
4
 
6
5
 
7
6
  class UnauthorizedError(CollibraAPIError):
8
7
  """Raised when authentication fails"""
9
- pass
10
8
 
11
9
 
12
10
  class ForbiddenError(CollibraAPIError):
13
11
  """Raised when access is forbidden"""
14
- pass
15
12
 
16
13
 
17
14
  class NotFoundError(CollibraAPIError):
18
15
  """Raised when resource is not found"""
19
- pass
20
16
 
21
17
 
22
18
  class ServerError(CollibraAPIError):
23
19
  """Raised when server returns 5xx errors"""
24
- pass
@@ -0,0 +1,120 @@
1
+ from .Base import BaseAPI
2
+
3
+
4
+ class Metadata(BaseAPI):
5
+ def __init__(self, connector):
6
+ super().__init__(connector)
7
+ self.__base_api = connector.api
8
+
9
+ def get_collibra_metadata(self):
10
+ """
11
+ Retrieve comprehensive metadata from Collibra including asset types,
12
+ relation types, responsibilities, statuses, attributes, communities,
13
+ domains, and domain types.
14
+ :return: Dictionary containing all metadata with names as keys and UUIDs as values.
15
+ """
16
+ metadata = {
17
+ "AssetType": {},
18
+ "Relation": {},
19
+ "Responsibility": {},
20
+ "Status": {},
21
+ "StringAttribute": {},
22
+ "Community": {},
23
+ "Domain": {},
24
+ "DomainType": {},
25
+ }
26
+
27
+ try:
28
+ # Get Asset Types
29
+ asset_types_response = self._get(url=f"{self.__base_api}/assetTypes")
30
+ asset_types_data = self._handle_response(asset_types_response)
31
+ for asset_type in asset_types_data.get("results", []):
32
+ metadata["AssetType"][asset_type["name"]] = asset_type["id"]
33
+
34
+ # Get Relation Types
35
+ relation_types_response = self._get(url=f"{self.__base_api}/relationTypes")
36
+ relation_types_data = self._handle_response(relation_types_response)
37
+ for relation_type in relation_types_data.get("results", []):
38
+ import re
39
+ source_name = re.sub(" ", "", relation_type["sourceType"]["name"])
40
+ target_name = re.sub(" ", "", relation_type["targetType"]["name"])
41
+ metadata["Relation"][f"{source_name}_{target_name}"] = relation_type["id"]
42
+
43
+ # Get Roles/Responsibilities
44
+ roles_response = self._get(url=f"{self.__base_api}/roles")
45
+ roles_data = self._handle_response(roles_response)
46
+ for role in roles_data.get("results", []):
47
+ metadata["Responsibility"][role["name"]] = role["id"]
48
+
49
+ # Get Statuses
50
+ statuses_response = self._get(url=f"{self.__base_api}/statuses")
51
+ statuses_data = self._handle_response(statuses_response)
52
+ for status in statuses_data.get("results", []):
53
+ metadata["Status"][status["name"]] = status["id"]
54
+
55
+ # Get Attribute Types
56
+ attributes_response = self._get(url=f"{self.__base_api}/attributeTypes")
57
+ attributes_data = self._handle_response(attributes_response)
58
+ for attribute in attributes_data.get("results", []):
59
+ metadata["StringAttribute"][attribute["name"]] = attribute["id"]
60
+
61
+ # Get Communities
62
+ communities_response = self._get(url=f"{self.__base_api}/communities")
63
+ communities_data = self._handle_response(communities_response)
64
+ for community in communities_data.get("results", []):
65
+ metadata["Community"][community["name"]] = community["id"]
66
+
67
+ # Get Domains (with pagination)
68
+ domains_params = {"limit": 1000, "offset": 0}
69
+ while True:
70
+ domains_response = self._get(url=f"{self.__base_api}/domains", params=domains_params)
71
+ domains_data = self._handle_response(domains_response)
72
+ for domain in domains_data.get("results", []):
73
+ metadata["Domain"][domain["name"]] = domain["id"]
74
+ if (
75
+ domains_data.get("offset", 0) + domains_data.get("limit", 0) >=
76
+ domains_data.get("total", 0)
77
+ ):
78
+ break
79
+ domains_params["offset"] += domains_params["limit"]
80
+
81
+ # Get Domain Types
82
+ domain_types_response = self._get(url=f"{self.__base_api}/domainTypes")
83
+ domain_types_data = self._handle_response(domain_types_response)
84
+ for domain_type in domain_types_data.get("results", []):
85
+ metadata["DomainType"][domain_type["name"]] = domain_type["id"]
86
+
87
+ return metadata
88
+
89
+ except Exception as e:
90
+ raise Exception(f"Error fetching Collibra metadata: {str(e)}") from e
91
+
92
+ def get_asset_types(self):
93
+ """Get all asset types."""
94
+ response = self._get(url=f"{self.__base_api}/assetTypes")
95
+ return self._handle_response(response)
96
+
97
+ def get_relation_types(self):
98
+ """Get all relation types."""
99
+ response = self._get(url=f"{self.__base_api}/relationTypes")
100
+ return self._handle_response(response)
101
+
102
+ def get_statuses(self):
103
+ """Get all statuses."""
104
+ response = self._get(url=f"{self.__base_api}/statuses")
105
+ return self._handle_response(response)
106
+
107
+ def get_attribute_types(self):
108
+ """Get all attribute types."""
109
+ response = self._get(url=f"{self.__base_api}/attributeTypes")
110
+ return self._handle_response(response)
111
+
112
+ def get_domain_types(self):
113
+ """Get all domain types."""
114
+ response = self._get(url=f"{self.__base_api}/domainTypes")
115
+ return self._handle_response(response)
116
+
117
+ def get_roles(self):
118
+ """Get all roles."""
119
+ response = self._get(url=f"{self.__base_api}/roles")
120
+ return self._handle_response(response)
@@ -0,0 +1,303 @@
1
+ import uuid
2
+ from .Base import BaseAPI
3
+
4
+
5
+ class Responsibility(BaseAPI):
6
+ def __init__(self, connector):
7
+ super().__init__(connector)
8
+ self.__base_api = connector.api + "/responsibilities"
9
+
10
+ def add_responsibility(
11
+ self,
12
+ role_id: str,
13
+ owner_id: str,
14
+ resource_id: str = None,
15
+ resource_type: str = None,
16
+ resource_discriminator: str = None
17
+ ):
18
+ """
19
+ Add a new responsibility. Assigns given user to resource with given role.
20
+ :param role_id: The ID of the role that should be assigned to user.
21
+ :param owner_id: The ID of the user who the responsibility is created for.
22
+ :param resource_id: The ID of the resource which the responsibility is created for.
23
+ If None, creates global responsibility.
24
+ :param resource_type: The type of the resource (e.g., Asset, Community, Domain, etc.).
25
+ :param resource_discriminator: The discriminator for resource type. Valid values: "Community", "Domain", "Asset"
26
+ :return: The responsibility ID.
27
+ """
28
+ # Validate required parameters
29
+ if not role_id or not owner_id:
30
+ raise ValueError("role_id and owner_id are required parameters")
31
+
32
+ # Validate UUIDs
33
+ for param_name, param_value in [("role_id", role_id), ("owner_id", owner_id)]:
34
+ if not isinstance(param_value, str):
35
+ raise ValueError(f"{param_name} must be a string")
36
+ try:
37
+ uuid.UUID(param_value)
38
+ except ValueError as exc:
39
+ raise ValueError(f"{param_name} must be a valid UUID") from exc
40
+
41
+ # Validate resource_id if provided
42
+ if resource_id is not None:
43
+ if not isinstance(resource_id, str):
44
+ raise ValueError("resource_id must be a string")
45
+ try:
46
+ uuid.UUID(resource_id)
47
+ except ValueError as exc:
48
+ raise ValueError("resource_id must be a valid UUID") from exc
49
+
50
+ # Validate resource_type if provided
51
+ valid_resource_types = [
52
+ "View", "Asset", "Community", "Domain", "AssetType", "DomainType", "Status", "User",
53
+ "Classification", "MatchUser", "Group", "Attribute", "StringAttribute", "ScriptAttribute",
54
+ "BooleanAttribute", "DateAttribute", "NumericAttribute", "SingleValueListAttribute",
55
+ "MultiValueListAttribute", "Comment", "Attachment", "Responsibility", "Workflow", "Job",
56
+ "Relation", "RelationType", "ComplexRelation", "ComplexRelationType", "ArticulationRule",
57
+ "Assignment", "ScopeRelation", "Trace", "ValidationRule", "DataQualityRule", "DataQualityMetric",
58
+ "Address", "InstantMessagingAccount", "Email", "PhoneNumber", "Website", "Activity",
59
+ "FormProperty", "WorkflowTask", "ActivityChange", "WorkflowInstance", "Role", "AttributeType",
60
+ "BooleanAttributeType", "DateAttributeType", "DateTimeAttributeType", "MultiValueListAttributeType",
61
+ "NumericAttributeType", "ScriptAttributeType", "SingleValueListAttributeType", "StringAttributeType",
62
+ "ViewSharingRule", "ViewAssignmentRule", "JdbcDriver", "File", "JdbcDriverJdbcIngestionProperties",
63
+ "CsvIngestionProperties", "ExcelIngestionProperties", "ConnectionStringParameter",
64
+ "AssignedCharacteristicType", "Notification", "Tag", "ComplexRelationLegType",
65
+ "ComplexRelationAttributeType", "ComplexRelationLeg", "BaseDataType", "AdvancedDataType",
66
+ "Diagram", "Picture", "DiagramPictureSharingRule", "DiagramPictureAssignmentRule", "Rating",
67
+ "ClassificationPhysicalData", "ConnectorContext"
68
+ ]
69
+
70
+ if resource_type is not None and resource_type not in valid_resource_types:
71
+ raise ValueError(
72
+ "resource_type must be one of the valid resource types. See API documentation for full list."
73
+ )
74
+
75
+ # Validate resource_discriminator if provided
76
+ valid_discriminators = ["Community", "Domain", "Asset"]
77
+ if resource_discriminator is not None and resource_discriminator not in valid_discriminators:
78
+ raise ValueError(f"resource_discriminator must be one of: {', '.join(valid_discriminators)}")
79
+
80
+ # Build request data - only include non-None values
81
+ data = {
82
+ "roleId": role_id,
83
+ "ownerId": owner_id
84
+ }
85
+
86
+ if resource_id is not None:
87
+ data["resourceId"] = resource_id
88
+ if resource_type is not None:
89
+ data["resourceType"] = resource_type
90
+ if resource_discriminator is not None:
91
+ data["resourceDiscriminator"] = resource_discriminator
92
+
93
+ response = self._post(url=self.__base_api, data=data)
94
+ result = self._handle_response(response)
95
+ return result.get("id")
96
+
97
+ def get_responsibility(self, responsibility_id: str):
98
+ """
99
+ Get details of a specific responsibility.
100
+ :param responsibility_id: The ID of the responsibility.
101
+ :return: Responsibility details.
102
+ """
103
+ if not responsibility_id:
104
+ raise ValueError("responsibility_id is required")
105
+ if not isinstance(responsibility_id, str):
106
+ raise ValueError("responsibility_id must be a string")
107
+
108
+ try:
109
+ uuid.UUID(responsibility_id)
110
+ except ValueError as exc:
111
+ raise ValueError("responsibility_id must be a valid UUID") from exc
112
+
113
+ response = self._get(url=f"{self.__base_api}/{responsibility_id}")
114
+ return self._handle_response(response)
115
+
116
+ def find_responsibilities(
117
+ self,
118
+ count_limit: int = -1,
119
+ exclude_empty_groups: bool = None,
120
+ global_only: bool = None,
121
+ include_inherited: bool = True,
122
+ limit: int = 0,
123
+ offset: int = 0,
124
+ owner_ids: list = None,
125
+ resource_ids: list = None,
126
+ role_ids: list = None,
127
+ sort_field: str = "LAST_MODIFIED",
128
+ sort_order: str = "DESC",
129
+ _type: str = None
130
+ ):
131
+ """
132
+ Find responsibilities matching the given search criteria.
133
+ :param count_limit: Limit the number of elements counted. -1 counts everything, 0 skips count.
134
+ :param exclude_empty_groups: Whether responsibilities assigned to empty groups should be excluded.
135
+ :param global_only: Whether only global responsibilities should be searched (deprecated).
136
+ :param include_inherited: Whether inherited responsibilities should be included.
137
+ :param limit: Maximum number of results to retrieve. 0 uses default, max 1000.
138
+ :param offset: First result to retrieve. 0 starts from beginning.
139
+ :param owner_ids: List of owner IDs to filter responsibilities by.
140
+ :param resource_ids: List of resource IDs to filter responsibilities by.
141
+ :param role_ids: List of role IDs to filter responsibilities by.
142
+ :param sort_field: Field to sort results by. Options: CREATED_BY, CREATED_ON, LAST_MODIFIED, NAME
143
+ :param sort_order: Sort order. Options: ASC, DESC
144
+ :param type: Type of responsibilities. Options: ALL, GLOBAL, RESOURCE
145
+ :return: List of responsibilities matching the criteria.
146
+ """
147
+ # Validate sort_field
148
+ valid_sort_fields = ["CREATED_BY", "CREATED_ON", "LAST_MODIFIED", "NAME"]
149
+ if sort_field not in valid_sort_fields:
150
+ raise ValueError(f"sort_field must be one of: {', '.join(valid_sort_fields)}")
151
+
152
+ # Validate sort_order
153
+ if sort_order not in ["ASC", "DESC"]:
154
+ raise ValueError("sort_order must be 'ASC' or 'DESC'")
155
+
156
+ # Validate limit
157
+ if limit < 0 or limit > 1000:
158
+ raise ValueError("limit must be between 0 and 1000")
159
+
160
+ # Validate type if provided
161
+ valid_types = ["ALL", "GLOBAL", "RESOURCE"]
162
+ if _type is not None and _type not in valid_types:
163
+ raise ValueError(f"type must be one of: {', '.join(valid_types)}")
164
+
165
+ # Validate that globalOnly and type are mutually exclusive
166
+ if global_only is not None and type is not None:
167
+ raise ValueError("globalOnly and type parameters are mutually exclusive")
168
+
169
+ # Validate owner_ids if provided
170
+ if owner_ids is not None:
171
+ if not isinstance(owner_ids, list):
172
+ raise ValueError("owner_ids must be a list")
173
+ for owner_id in owner_ids:
174
+ if not isinstance(owner_id, str):
175
+ raise ValueError("owner_id must be a string")
176
+ try:
177
+ uuid.UUID(owner_id)
178
+ except ValueError as exc:
179
+ raise ValueError("owner_id must be a valid UUID") from exc
180
+
181
+ # Validate resource_ids if provided
182
+ if resource_ids is not None:
183
+ if not isinstance(resource_ids, list):
184
+ raise ValueError("resource_ids must be a list")
185
+ for resource_id in resource_ids:
186
+ if not isinstance(resource_id, str):
187
+ raise ValueError("resource_id must be a string")
188
+ try:
189
+ uuid.UUID(resource_id)
190
+ except ValueError as exc:
191
+ raise ValueError("resource_id must be a valid UUID") from exc
192
+
193
+ # Validate role_ids if provided
194
+ if role_ids is not None:
195
+ if not isinstance(role_ids, list):
196
+ raise ValueError("role_ids must be a list")
197
+ for role_id in role_ids:
198
+ if not isinstance(role_id, str):
199
+ raise ValueError("role_id must be a string")
200
+ try:
201
+ uuid.UUID(role_id)
202
+ except ValueError as exc:
203
+ raise ValueError("role_id must be a valid UUID") from exc
204
+
205
+ # Build parameters - only include non-default values
206
+ params = {}
207
+
208
+ if count_limit != -1:
209
+ params["countLimit"] = count_limit
210
+ if exclude_empty_groups is not None:
211
+ params["excludeEmptyGroups"] = exclude_empty_groups
212
+ if global_only is not None:
213
+ params["globalOnly"] = global_only
214
+ if include_inherited is not True:
215
+ params["includeInherited"] = include_inherited
216
+ if limit != 0:
217
+ params["limit"] = limit
218
+ if offset != 0:
219
+ params["offset"] = offset
220
+ if owner_ids is not None:
221
+ params["ownerIds"] = owner_ids
222
+ if resource_ids is not None:
223
+ params["resourceIds"] = resource_ids
224
+ if role_ids is not None:
225
+ params["roleIds"] = role_ids
226
+ if sort_field != "LAST_MODIFIED":
227
+ params["sortField"] = sort_field
228
+ if sort_order != "DESC":
229
+ params["sortOrder"] = sort_order
230
+ if type is not None:
231
+ params["type"] = type
232
+
233
+ response = self._get(params=params)
234
+ return self._handle_response(response)
235
+
236
+ def get_asset_responsibilities(self, asset_id: str, role_ids: list = None):
237
+ """
238
+ Get responsibilities for an asset (convenience method).
239
+ :param asset_id: The ID of the asset.
240
+ :param role_ids: Optional list of role IDs to filter by.
241
+ :return: List of responsibilities.
242
+ """
243
+ if not asset_id:
244
+ raise ValueError("asset_id is required")
245
+ if not isinstance(asset_id, str):
246
+ raise ValueError("asset_id must be a string")
247
+
248
+ try:
249
+ uuid.UUID(asset_id)
250
+ except ValueError as exc:
251
+ raise ValueError("asset_id must be a valid UUID") from exc
252
+
253
+ return self.find_responsibilities(
254
+ resource_ids=[asset_id],
255
+ role_ids=role_ids
256
+ )
257
+
258
+ def get_user_responsibilities(self, user_id: str, role_id: str = None):
259
+ """
260
+ Get responsibilities for a user (convenience method).
261
+ :param user_id: The ID of the user.
262
+ :param role_id: Optional role ID to filter by.
263
+ :return: List of responsibilities.
264
+ """
265
+ if not user_id:
266
+ raise ValueError("user_id is required")
267
+ if not isinstance(user_id, str):
268
+ raise ValueError("user_id must be a string")
269
+
270
+ try:
271
+ uuid.UUID(user_id)
272
+ except ValueError as exc:
273
+ raise ValueError("user_id must be a valid UUID") from exc
274
+
275
+ role_ids = [role_id] if role_id else None
276
+ return self.find_responsibilities(
277
+ owner_ids=[user_id],
278
+ role_ids=role_ids
279
+ )
280
+
281
+ def get_global_responsibilities(self, role_ids: list = None):
282
+ """
283
+ Get global responsibilities (convenience method).
284
+ :param role_ids: Optional list of role IDs to filter by.
285
+ :return: List of global responsibilities.
286
+ """
287
+ return self.find_responsibilities(
288
+ _type="GLOBAL",
289
+ role_ids=role_ids
290
+ )
291
+
292
+ def get_resource_responsibilities(self, resource_ids: list = None, role_ids: list = None):
293
+ """
294
+ Get resource-specific responsibilities (convenience method).
295
+ :param resource_ids: Optional list of resource IDs to filter by.
296
+ :param role_ids: Optional list of role IDs to filter by.
297
+ :return: List of resource responsibilities.
298
+ """
299
+ return self.find_responsibilities(
300
+ _type="RESOURCE",
301
+ resource_ids=resource_ids,
302
+ role_ids=role_ids
303
+ )