collibra-connector 1.0.7__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.
- collibra_connector/__init__.py +21 -21
- collibra_connector/api/Asset.py +218 -19
- collibra_connector/api/Base.py +92 -11
- collibra_connector/api/Comment.py +125 -0
- collibra_connector/api/Community.py +112 -0
- collibra_connector/api/Domain.py +116 -0
- collibra_connector/api/Exceptions.py +5 -5
- collibra_connector/api/Metadata.py +120 -0
- collibra_connector/api/Responsibility.py +303 -0
- collibra_connector/api/User.py +203 -0
- collibra_connector/api/Workflow.py +260 -0
- collibra_connector/api/__init__.py +14 -0
- collibra_connector/connector.py +23 -3
- collibra_connector-1.0.10a0.dist-info/METADATA +157 -0
- collibra_connector-1.0.10a0.dist-info/RECORD +18 -0
- collibra_connector-1.0.7.dist-info/METADATA +0 -27
- collibra_connector-1.0.7.dist-info/RECORD +0 -11
- {collibra_connector-1.0.7.dist-info → collibra_connector-1.0.10a0.dist-info}/WHEEL +0 -0
- {collibra_connector-1.0.7.dist-info → collibra_connector-1.0.10a0.dist-info}/licenses/LICENSE +0 -0
- {collibra_connector-1.0.7.dist-info → collibra_connector-1.0.10a0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
from .Base import BaseAPI
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class User(BaseAPI):
|
|
6
|
+
def __init__(self, connector):
|
|
7
|
+
super().__init__(connector)
|
|
8
|
+
self.__base_api = connector.api + "/users"
|
|
9
|
+
|
|
10
|
+
def get_user(self, user_id: str):
|
|
11
|
+
"""
|
|
12
|
+
Get user information by user ID.
|
|
13
|
+
:param user_id: The ID of the user.
|
|
14
|
+
:return: User details.
|
|
15
|
+
"""
|
|
16
|
+
if not user_id:
|
|
17
|
+
raise ValueError("user_id is required")
|
|
18
|
+
if not isinstance(user_id, str):
|
|
19
|
+
raise ValueError("user_id must be a string")
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
uuid.UUID(user_id)
|
|
23
|
+
except ValueError as exc:
|
|
24
|
+
raise ValueError("user_id must be a valid UUID") from exc
|
|
25
|
+
|
|
26
|
+
response = self._get(url=f"{self.__base_api}/{user_id}")
|
|
27
|
+
return self._handle_response(response)
|
|
28
|
+
|
|
29
|
+
def get_user_by_username(self, username: str):
|
|
30
|
+
"""
|
|
31
|
+
Get user ID by username (convenience method).
|
|
32
|
+
:param username: The username to search for.
|
|
33
|
+
:return: User ID if found, None otherwise.
|
|
34
|
+
"""
|
|
35
|
+
if not username:
|
|
36
|
+
raise ValueError("username is required")
|
|
37
|
+
if not isinstance(username, str):
|
|
38
|
+
raise ValueError("username must be a string")
|
|
39
|
+
|
|
40
|
+
result = self.find_users(
|
|
41
|
+
name=username,
|
|
42
|
+
name_search_fields=["USERNAME"],
|
|
43
|
+
include_disabled=True,
|
|
44
|
+
limit=1
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
if result.get("total", 0) > 0:
|
|
48
|
+
return result.get("results", [{}])[0].get("id", "")
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
def create_user(self, username: str, email_address: str):
|
|
52
|
+
"""
|
|
53
|
+
Create a new user.
|
|
54
|
+
:param username: The username for the new user.
|
|
55
|
+
:param email_address: The email address for the new user.
|
|
56
|
+
:return: The created user details.
|
|
57
|
+
"""
|
|
58
|
+
if not username or not email_address:
|
|
59
|
+
raise ValueError("username and email_address are required")
|
|
60
|
+
if not isinstance(username, str) or not isinstance(email_address, str):
|
|
61
|
+
raise ValueError("username and email_address must be strings")
|
|
62
|
+
|
|
63
|
+
data = {
|
|
64
|
+
"userName": username,
|
|
65
|
+
"emailAddress": email_address
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
response = self._post(url=self.__base_api, data=data)
|
|
69
|
+
return self._handle_response(response)
|
|
70
|
+
|
|
71
|
+
def find_users(
|
|
72
|
+
self,
|
|
73
|
+
count_limit: int = -1,
|
|
74
|
+
group_id: str = None,
|
|
75
|
+
include_disabled: bool = None,
|
|
76
|
+
limit: int = 0,
|
|
77
|
+
name: str = None,
|
|
78
|
+
name_search_fields: list = None,
|
|
79
|
+
offset: int = 0,
|
|
80
|
+
only_logged_in: bool = None,
|
|
81
|
+
sort_field: str = "USERNAME",
|
|
82
|
+
sort_order: str = "ASC",
|
|
83
|
+
user_ids: list = None
|
|
84
|
+
):
|
|
85
|
+
"""
|
|
86
|
+
Find users based on various criteria.
|
|
87
|
+
:param count_limit: Limit the number of elements that will be counted. -1 counts everything, 0 skips count.
|
|
88
|
+
:param group_id: The ID of the group the searched users should belong to.
|
|
89
|
+
:param include_disabled: Whether disabled users should be included in the search results.
|
|
90
|
+
:param limit: Maximum number of results to retrieve (0 = default limit, max 1000).
|
|
91
|
+
:param name: Name to search for in the fields specified by name_search_fields.
|
|
92
|
+
:param name_search_fields: User fields to search for the 'name' parameter.
|
|
93
|
+
:param offset: First result to retrieve (0-based).
|
|
94
|
+
:param only_logged_in: Whether only currently logged in users should be returned.
|
|
95
|
+
:param sort_field: Field for sorting.
|
|
96
|
+
:param sort_order: Order of sorting (ASC/DESC).
|
|
97
|
+
:param user_ids: List of user IDs to look for.
|
|
98
|
+
:return: Search results with users matching the criteria.
|
|
99
|
+
"""
|
|
100
|
+
# Validate count_limit
|
|
101
|
+
if not isinstance(count_limit, int):
|
|
102
|
+
raise ValueError("count_limit must be an integer")
|
|
103
|
+
|
|
104
|
+
# Validate group_id if provided
|
|
105
|
+
if group_id is not None:
|
|
106
|
+
if not isinstance(group_id, str):
|
|
107
|
+
raise ValueError("group_id must be a string")
|
|
108
|
+
try:
|
|
109
|
+
uuid.UUID(group_id)
|
|
110
|
+
except ValueError as exc:
|
|
111
|
+
raise ValueError("group_id must be a valid UUID") from exc
|
|
112
|
+
|
|
113
|
+
# Validate include_disabled
|
|
114
|
+
if include_disabled is not None and not isinstance(include_disabled, bool):
|
|
115
|
+
raise ValueError("include_disabled must be a boolean")
|
|
116
|
+
|
|
117
|
+
# Validate limit
|
|
118
|
+
if not isinstance(limit, int) or limit < 0:
|
|
119
|
+
raise ValueError("limit must be a non-negative integer")
|
|
120
|
+
if limit > 1000:
|
|
121
|
+
raise ValueError("limit cannot exceed 1000")
|
|
122
|
+
|
|
123
|
+
# Validate name
|
|
124
|
+
if name is not None and not isinstance(name, str):
|
|
125
|
+
raise ValueError("name must be a string")
|
|
126
|
+
|
|
127
|
+
# Validate name_search_fields
|
|
128
|
+
valid_name_search_fields = [
|
|
129
|
+
"USERNAME", "FIRSTNAME", "LASTNAME", "LASTNAME_FIRSTNAME",
|
|
130
|
+
"FIRSTNAME_LASTNAME", "EMAIL"
|
|
131
|
+
]
|
|
132
|
+
if name_search_fields is not None:
|
|
133
|
+
if not isinstance(name_search_fields, list):
|
|
134
|
+
raise ValueError("name_search_fields must be a list")
|
|
135
|
+
for field in name_search_fields:
|
|
136
|
+
if field not in valid_name_search_fields:
|
|
137
|
+
raise ValueError(f"Invalid name search field: {field}. "
|
|
138
|
+
f"Allowed values: {valid_name_search_fields}")
|
|
139
|
+
# Validate offset
|
|
140
|
+
if not isinstance(offset, int) or offset < 0:
|
|
141
|
+
raise ValueError("offset must be a non-negative integer")
|
|
142
|
+
|
|
143
|
+
# Validate only_logged_in
|
|
144
|
+
if only_logged_in is not None and not isinstance(only_logged_in, bool):
|
|
145
|
+
raise ValueError("only_logged_in must be a boolean")
|
|
146
|
+
# Validate sort_field
|
|
147
|
+
valid_sort_fields = [
|
|
148
|
+
"USERNAME", "FIRSTNAME", "LASTNAME", "LASTNAME_FIRSTNAME",
|
|
149
|
+
"FIRSTNAME_LASTNAME", "EMAIL"
|
|
150
|
+
]
|
|
151
|
+
if sort_field not in valid_sort_fields:
|
|
152
|
+
raise ValueError(f"Invalid sort field: {sort_field}. "
|
|
153
|
+
f"Allowed values: {valid_sort_fields}")
|
|
154
|
+
# Validate sort_order
|
|
155
|
+
if sort_order not in ["ASC", "DESC"]:
|
|
156
|
+
raise ValueError("sort_order must be 'ASC' or 'DESC'")
|
|
157
|
+
|
|
158
|
+
# Validate user_ids
|
|
159
|
+
if user_ids is not None:
|
|
160
|
+
if not isinstance(user_ids, list):
|
|
161
|
+
raise ValueError("user_ids must be a list")
|
|
162
|
+
for user_id in user_ids:
|
|
163
|
+
if not isinstance(user_id, str):
|
|
164
|
+
raise ValueError("All user IDs must be strings")
|
|
165
|
+
try:
|
|
166
|
+
uuid.UUID(user_id)
|
|
167
|
+
except ValueError as exc:
|
|
168
|
+
raise ValueError(f"Invalid UUID in user_ids: {user_id}") from exc
|
|
169
|
+
|
|
170
|
+
# Build parameters
|
|
171
|
+
params = {
|
|
172
|
+
"countLimit": count_limit,
|
|
173
|
+
"limit": limit,
|
|
174
|
+
"offset": offset,
|
|
175
|
+
"sortField": sort_field,
|
|
176
|
+
"sortOrder": sort_order
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
# Add optional parameters
|
|
180
|
+
if group_id is not None:
|
|
181
|
+
params["groupId"] = group_id
|
|
182
|
+
|
|
183
|
+
if include_disabled is not None:
|
|
184
|
+
params["includeDisabled"] = include_disabled
|
|
185
|
+
|
|
186
|
+
if name is not None:
|
|
187
|
+
params["name"] = name
|
|
188
|
+
|
|
189
|
+
if name_search_fields is not None:
|
|
190
|
+
params["nameSearchFields"] = name_search_fields
|
|
191
|
+
|
|
192
|
+
if only_logged_in is not None:
|
|
193
|
+
params["onlyLoggedIn"] = only_logged_in
|
|
194
|
+
|
|
195
|
+
if user_ids is not None:
|
|
196
|
+
# The API expects multiple userId parameters for each ID
|
|
197
|
+
for user_id in user_ids:
|
|
198
|
+
if "userId" not in params:
|
|
199
|
+
params["userId"] = []
|
|
200
|
+
params["userId"].append(user_id)
|
|
201
|
+
|
|
202
|
+
response = self._get(params=params)
|
|
203
|
+
return self._handle_response(response)
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
from .Base import BaseAPI
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Workflow(BaseAPI):
|
|
6
|
+
def __init__(self, connector):
|
|
7
|
+
super().__init__(connector)
|
|
8
|
+
self.__base_api = connector.api
|
|
9
|
+
|
|
10
|
+
def start_workflow_instance(
|
|
11
|
+
self,
|
|
12
|
+
workflow_definition_id: str,
|
|
13
|
+
asset_id: str = None,
|
|
14
|
+
return_all: bool = False
|
|
15
|
+
):
|
|
16
|
+
"""
|
|
17
|
+
Start a workflow instance.
|
|
18
|
+
:param workflow_definition_id: The ID of the workflow definition.
|
|
19
|
+
:param asset_id: Optional asset ID to associate with the workflow.
|
|
20
|
+
:param return_all: Whether to return all workflow data or just the ID.
|
|
21
|
+
:return: Workflow instance ID or full response data.
|
|
22
|
+
"""
|
|
23
|
+
if not workflow_definition_id:
|
|
24
|
+
raise ValueError("workflow_definition_id is required")
|
|
25
|
+
if not isinstance(workflow_definition_id, str):
|
|
26
|
+
raise ValueError("workflow_definition_id must be a string")
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
uuid.UUID(workflow_definition_id)
|
|
30
|
+
except ValueError as exc:
|
|
31
|
+
raise ValueError("workflow_definition_id must be a valid UUID") from exc
|
|
32
|
+
|
|
33
|
+
data = {
|
|
34
|
+
"workflowDefinitionId": workflow_definition_id,
|
|
35
|
+
"sendNotification": True
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if asset_id:
|
|
39
|
+
if not isinstance(asset_id, str):
|
|
40
|
+
raise ValueError("asset_id must be a string")
|
|
41
|
+
try:
|
|
42
|
+
uuid.UUID(asset_id)
|
|
43
|
+
except ValueError as exc:
|
|
44
|
+
raise ValueError("asset_id must be a valid UUID") from exc
|
|
45
|
+
|
|
46
|
+
data.update({
|
|
47
|
+
"businessItemIds": [asset_id],
|
|
48
|
+
"businessItemType": "ASSET",
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
response = self._post(url=f"{self.__base_api}/workflowInstances", data=data)
|
|
52
|
+
result = self._handle_response(response)
|
|
53
|
+
|
|
54
|
+
if return_all:
|
|
55
|
+
return result
|
|
56
|
+
return result[0].get("id") if result else None
|
|
57
|
+
|
|
58
|
+
def find_workflow_task(
|
|
59
|
+
self,
|
|
60
|
+
business_item_id: str = None,
|
|
61
|
+
business_item_name: str = None,
|
|
62
|
+
business_item_type: str = None,
|
|
63
|
+
count_limit: int = -1,
|
|
64
|
+
create_date: str = None,
|
|
65
|
+
description: str = None,
|
|
66
|
+
due_date: str = None,
|
|
67
|
+
limit: int = 0,
|
|
68
|
+
offset: int = 0,
|
|
69
|
+
sort_field: str = "DUE_DATE",
|
|
70
|
+
sort_order: str = "DESC",
|
|
71
|
+
title: str = None,
|
|
72
|
+
user_id: str = None,
|
|
73
|
+
workflow_task_user_relation: str = "ALL"
|
|
74
|
+
):
|
|
75
|
+
"""
|
|
76
|
+
Find workflow tasks matching the given search criteria.
|
|
77
|
+
:param business_item_id: ID of the business item associated with the task.
|
|
78
|
+
:param business_item_name: Name of the business item associated with the task.
|
|
79
|
+
:param business_item_type: Type of the business item (e.g., ASSET).
|
|
80
|
+
:param count_limit: Limit elements counted. -1 counts all, 0 skips count.
|
|
81
|
+
:param create_date: Creation date of the task.
|
|
82
|
+
:param description: Description of the task.
|
|
83
|
+
:param due_date: Due date of the task.
|
|
84
|
+
:param limit: Maximum results to retrieve. 0 uses default, max 1000.
|
|
85
|
+
:param offset: First result to retrieve (deprecated, use cursor instead).
|
|
86
|
+
:param sort_field: Field to sort results by. Default is DUE_DATE.
|
|
87
|
+
:param sort_order: Sort order. Options: ASC, DESC. Default is DESC.
|
|
88
|
+
:param title: Title of the task
|
|
89
|
+
:param user_id: ID of the user associated with the task.
|
|
90
|
+
:param workflow_task_user_relation: Relation of the user to the task. Options: ALL, ASSIGNED, INVOLVED.
|
|
91
|
+
:return: List of workflow tasks matching criteria.
|
|
92
|
+
"""
|
|
93
|
+
# Validate business_item_id if provided
|
|
94
|
+
if business_item_id is not None:
|
|
95
|
+
if not isinstance(business_item_id, str):
|
|
96
|
+
raise ValueError("business_item_id must be a string")
|
|
97
|
+
try:
|
|
98
|
+
uuid.UUID(business_item_id)
|
|
99
|
+
except ValueError as exc:
|
|
100
|
+
raise ValueError("business_item_id must be a valid UUID") from exc
|
|
101
|
+
|
|
102
|
+
# Validate business_item_type if provided
|
|
103
|
+
if business_item_type is not None and not isinstance(business_item_type, str):
|
|
104
|
+
raise ValueError("business_item_type must be a string")
|
|
105
|
+
|
|
106
|
+
# Validate count_limit
|
|
107
|
+
if not isinstance(count_limit, int):
|
|
108
|
+
raise ValueError("count_limit must be an integer")
|
|
109
|
+
|
|
110
|
+
# Validate create_date if provided
|
|
111
|
+
if create_date is not None and not isinstance(create_date, str):
|
|
112
|
+
raise ValueError("create_date must be a string")
|
|
113
|
+
|
|
114
|
+
# Validate description if provided
|
|
115
|
+
if description is not None and not isinstance(description, str):
|
|
116
|
+
raise ValueError("description must be a string")
|
|
117
|
+
|
|
118
|
+
# Validate due_date if provided
|
|
119
|
+
if due_date is not None and not isinstance(due_date, str):
|
|
120
|
+
raise ValueError("due_date must be a string")
|
|
121
|
+
|
|
122
|
+
# Validate limit
|
|
123
|
+
if not isinstance(limit, int) or limit < 0:
|
|
124
|
+
raise ValueError("limit must be a non-negative integer")
|
|
125
|
+
if limit > 1000:
|
|
126
|
+
raise ValueError("limit cannot exceed 1000")
|
|
127
|
+
|
|
128
|
+
# Validate offset
|
|
129
|
+
if not isinstance(offset, int) or offset < 0:
|
|
130
|
+
raise ValueError("offset must be a non-negative integer")
|
|
131
|
+
|
|
132
|
+
# Validate sort_field
|
|
133
|
+
valid_sort_fields = ["DUE_DATE", "CREATE_DATE", "TITLE"]
|
|
134
|
+
if sort_field not in valid_sort_fields:
|
|
135
|
+
raise ValueError(f"sort_field must be one of: {', '.join(valid_sort_fields)}")
|
|
136
|
+
|
|
137
|
+
# Validate sort_order
|
|
138
|
+
if sort_order not in ["ASC", "DESC"]:
|
|
139
|
+
raise ValueError("sort_order must be 'ASC' or 'DESC'")
|
|
140
|
+
|
|
141
|
+
# Validate title if provided
|
|
142
|
+
if title is not None and not isinstance(title, str):
|
|
143
|
+
raise ValueError("title must be a string")
|
|
144
|
+
|
|
145
|
+
# Validate user_id if provided
|
|
146
|
+
if user_id is not None:
|
|
147
|
+
if not isinstance(user_id, str):
|
|
148
|
+
raise ValueError("user_id must be a string")
|
|
149
|
+
try:
|
|
150
|
+
uuid.UUID(user_id)
|
|
151
|
+
except ValueError as exc:
|
|
152
|
+
raise ValueError("user_id must be a valid UUID") from exc
|
|
153
|
+
|
|
154
|
+
# Validate workflow_task_user_relation
|
|
155
|
+
valid_relations = ["ALL", "ASSIGNED", "INVOLVED"]
|
|
156
|
+
if workflow_task_user_relation not in valid_relations:
|
|
157
|
+
raise ValueError(f"workflow_task_user_relation must be one of: {', '.join(valid_relations)}")
|
|
158
|
+
|
|
159
|
+
# Build parameters - only include non-default values
|
|
160
|
+
params = {
|
|
161
|
+
"countLimit": count_limit,
|
|
162
|
+
"limit": limit,
|
|
163
|
+
"offset": offset,
|
|
164
|
+
"sortField": sort_field,
|
|
165
|
+
"sortOrder": sort_order,
|
|
166
|
+
"workflowTaskUserRelation": workflow_task_user_relation
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if business_item_id is not None:
|
|
170
|
+
params["businessItemId"] = business_item_id
|
|
171
|
+
if business_item_name is not None:
|
|
172
|
+
params["businessItemName"] = business_item_name
|
|
173
|
+
if business_item_type is not None:
|
|
174
|
+
params["businessItemType"] = business_item_type
|
|
175
|
+
if create_date is not None:
|
|
176
|
+
params["createDate"] = create_date
|
|
177
|
+
if description is not None:
|
|
178
|
+
params["description"] = description
|
|
179
|
+
if due_date is not None:
|
|
180
|
+
params["dueDate"] = due_date
|
|
181
|
+
if title is not None:
|
|
182
|
+
params["title"] = title
|
|
183
|
+
if user_id is not None:
|
|
184
|
+
params["userId"] = user_id
|
|
185
|
+
|
|
186
|
+
response = self._get(url=f"{self.__base_api}/workflowTasks", params=params)
|
|
187
|
+
return self._handle_response(response)
|
|
188
|
+
|
|
189
|
+
def get_workflow_task_id(self, instance_id: str, workflow_definition_id: str):
|
|
190
|
+
"""
|
|
191
|
+
Get the task ID for a workflow instance.
|
|
192
|
+
:param instance_id: The workflow instance ID.
|
|
193
|
+
:param workflow_definition_id: The workflow definition ID.
|
|
194
|
+
:return: The task ID.
|
|
195
|
+
"""
|
|
196
|
+
if not all([instance_id, workflow_definition_id]):
|
|
197
|
+
raise ValueError("instance_id and workflow_definition_id are required")
|
|
198
|
+
|
|
199
|
+
for param_name, param_value in [
|
|
200
|
+
("instance_id", instance_id), ("workflow_definition_id", workflow_definition_id)
|
|
201
|
+
]:
|
|
202
|
+
if not isinstance(param_value, str):
|
|
203
|
+
raise ValueError(f"{param_name} must be a string")
|
|
204
|
+
try:
|
|
205
|
+
uuid.UUID(param_value)
|
|
206
|
+
except ValueError as exc:
|
|
207
|
+
raise ValueError(f"{param_name} must be a valid UUID") from exc
|
|
208
|
+
|
|
209
|
+
params = {
|
|
210
|
+
"offset": 0,
|
|
211
|
+
"limit": 0,
|
|
212
|
+
"countLimit": -1,
|
|
213
|
+
"workflowDefinitionId": workflow_definition_id,
|
|
214
|
+
"instanceId": instance_id,
|
|
215
|
+
"sortField": "START_DATE",
|
|
216
|
+
"sortOrder": "DESC",
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
response = self._get(url=f"{self.__base_api}/workflowInstances", params=params)
|
|
220
|
+
result = self._handle_response(response)
|
|
221
|
+
|
|
222
|
+
tasks = result.get("results", [{}])[0].get("tasks", [])
|
|
223
|
+
return tasks[0].get("id") if tasks else None
|
|
224
|
+
|
|
225
|
+
def complete_workflow_task(self, task_ids: list[str], task_form_properties: dict):
|
|
226
|
+
"""
|
|
227
|
+
Complete a workflow task.
|
|
228
|
+
:param task_ids: The IDs of the tasks to complete.
|
|
229
|
+
:param task_form_properties: The form properties for the tasks.
|
|
230
|
+
:return: The response from completing the tasks.
|
|
231
|
+
"""
|
|
232
|
+
if not task_ids or not isinstance(task_ids, list):
|
|
233
|
+
raise ValueError("task_ids must be a non-empty list")
|
|
234
|
+
if not all(isinstance(task_id, str) for task_id in task_ids):
|
|
235
|
+
raise ValueError("All task_ids must be strings")
|
|
236
|
+
|
|
237
|
+
response = self._post(
|
|
238
|
+
url=f"{self.__base_api}/workflowTasks/completed",
|
|
239
|
+
data={"taskIds": task_ids, "taskFormProperties": task_form_properties}
|
|
240
|
+
)
|
|
241
|
+
return self._handle_response(response)
|
|
242
|
+
|
|
243
|
+
def get_task_form_data(self, task_id: str):
|
|
244
|
+
"""
|
|
245
|
+
Get form data for a workflow task.
|
|
246
|
+
:param task_id: The ID of the workflow task.
|
|
247
|
+
:return: The task form data.
|
|
248
|
+
"""
|
|
249
|
+
if not task_id:
|
|
250
|
+
raise ValueError("task_id is required")
|
|
251
|
+
if not isinstance(task_id, str):
|
|
252
|
+
raise ValueError("task_id must be a string")
|
|
253
|
+
|
|
254
|
+
try:
|
|
255
|
+
uuid.UUID(task_id)
|
|
256
|
+
except ValueError as exc:
|
|
257
|
+
raise ValueError("task_id must be a valid UUID") from exc
|
|
258
|
+
|
|
259
|
+
response = self._get(url=f"{self.__base_api}/workflowTasks/{task_id}/taskFormData")
|
|
260
|
+
return self._handle_response(response)
|
|
@@ -1,2 +1,16 @@
|
|
|
1
1
|
from .Asset import Asset
|
|
2
2
|
from .Base import BaseAPI
|
|
3
|
+
from .Community import Community
|
|
4
|
+
from .Domain import Domain
|
|
5
|
+
from .User import User
|
|
6
|
+
from .Responsibility import Responsibility
|
|
7
|
+
from .Workflow import Workflow
|
|
8
|
+
from .Metadata import Metadata
|
|
9
|
+
from .Comment import Comment
|
|
10
|
+
from .Exceptions import (
|
|
11
|
+
CollibraAPIError,
|
|
12
|
+
UnauthorizedError,
|
|
13
|
+
ForbiddenError,
|
|
14
|
+
NotFoundError,
|
|
15
|
+
ServerError
|
|
16
|
+
)
|
collibra_connector/connector.py
CHANGED
|
@@ -2,7 +2,18 @@ import logging
|
|
|
2
2
|
import requests
|
|
3
3
|
from requests.auth import HTTPBasicAuth
|
|
4
4
|
|
|
5
|
-
from .api import
|
|
5
|
+
from .api import (
|
|
6
|
+
Asset,
|
|
7
|
+
Community,
|
|
8
|
+
Domain,
|
|
9
|
+
User,
|
|
10
|
+
Responsibility,
|
|
11
|
+
Workflow,
|
|
12
|
+
Metadata,
|
|
13
|
+
Comment
|
|
14
|
+
)
|
|
15
|
+
from .api.Utils import CollibraUtils
|
|
16
|
+
|
|
6
17
|
|
|
7
18
|
class CollibraConnector():
|
|
8
19
|
"""
|
|
@@ -23,7 +34,16 @@ class CollibraConnector():
|
|
|
23
34
|
self.__base_url = api
|
|
24
35
|
self.__timeout = timeout
|
|
25
36
|
|
|
37
|
+
# Initialize all API classes
|
|
26
38
|
self.asset = Asset(self)
|
|
39
|
+
self.community = Community(self)
|
|
40
|
+
self.domain = Domain(self)
|
|
41
|
+
self.user = User(self)
|
|
42
|
+
self.responsibility = Responsibility(self)
|
|
43
|
+
self.workflow = Workflow(self)
|
|
44
|
+
self.metadata = Metadata(self)
|
|
45
|
+
self.comment = Comment(self)
|
|
46
|
+
self.utils = CollibraUtils(self)
|
|
27
47
|
|
|
28
48
|
logging.basicConfig(level=logging.INFO)
|
|
29
49
|
self.logger = logging.getLogger(__name__)
|
|
@@ -35,7 +55,7 @@ class CollibraConnector():
|
|
|
35
55
|
"""Test the connection to Collibra API"""
|
|
36
56
|
try:
|
|
37
57
|
response = requests.get(
|
|
38
|
-
f"{self.__api}/
|
|
58
|
+
f"{self.__api}/auth/sessions/current",
|
|
39
59
|
auth=self.__auth,
|
|
40
60
|
timeout=self.__timeout
|
|
41
61
|
)
|
|
@@ -54,4 +74,4 @@ class CollibraConnector():
|
|
|
54
74
|
|
|
55
75
|
@property
|
|
56
76
|
def base_url(self):
|
|
57
|
-
return self.__base_url
|
|
77
|
+
return self.__base_url
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: collibra-connector
|
|
3
|
+
Version: 1.0.10a0
|
|
4
|
+
Summary: An UNOFFICIAL standard Python connector for the Collibra Data Governance Center API.
|
|
5
|
+
Author-email: Raül Dalgamonni <rauldalgamonnialonso@gmail.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/rauldaal/collibra-python-connector
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/rauldaal/collibra-python-connector
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Requires-Python: >=3.8
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: requests>=2.20.0
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# Collibra Python Connector
|
|
20
|
+
|
|
21
|
+
An **UNOFFICIAL** comprehensive Python connector for the Collibra Data Governance Center API.
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- 🚀 **Complete API Coverage**: Asset, Community, Domain, User, Responsibility, Workflow, Metadata, and Comment management
|
|
26
|
+
- 🔄 **Automatic Retry Logic**: Built-in retry mechanism for robust API calls
|
|
27
|
+
- ✅ **Input Validation**: Comprehensive parameter validation with clear error messages
|
|
28
|
+
- 🏗️ **Clean Architecture**: Well-structured, extensible codebase with separation of concerns
|
|
29
|
+
- 📝 **Type Hints**: Full type annotations for better IDE support
|
|
30
|
+
- 🛡️ **Error Handling**: Custom exception hierarchy for different error types
|
|
31
|
+
- 🔧 **Utility Functions**: Helper methods for complex operations and bulk operations
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install collibra-connector
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from collibra_connector import CollibraConnector
|
|
43
|
+
|
|
44
|
+
# Initialize the connector
|
|
45
|
+
connector = CollibraConnector(
|
|
46
|
+
api="https://your-collibra-instance.com",
|
|
47
|
+
username="your-username",
|
|
48
|
+
password="your-password",
|
|
49
|
+
timeout=30
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Test connection
|
|
53
|
+
if connector.test_connection():
|
|
54
|
+
print("Connected successfully!")
|
|
55
|
+
|
|
56
|
+
# Get all metadata
|
|
57
|
+
metadata = connector.metadata.get_collibra_metadata()
|
|
58
|
+
print(f"Found {len(metadata['AssetType'])} asset types")
|
|
59
|
+
|
|
60
|
+
# Find communities
|
|
61
|
+
communities = connector.community.find_communities()
|
|
62
|
+
for community in communities.get("results", []):
|
|
63
|
+
print(f"Community: {community['name']}")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## API Reference
|
|
67
|
+
|
|
68
|
+
### Assets
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
# Get an asset
|
|
72
|
+
asset = connector.asset.get_asset("asset-uuid")
|
|
73
|
+
|
|
74
|
+
# Create an asset
|
|
75
|
+
new_asset = connector.asset.add_asset(
|
|
76
|
+
name="My New Asset",
|
|
77
|
+
domain_id="domain-uuid",
|
|
78
|
+
display_name="My Asset Display Name",
|
|
79
|
+
type_id="asset-type-uuid"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# Find assets
|
|
83
|
+
assets = connector.asset.find_assets(
|
|
84
|
+
community_id="community-uuid",
|
|
85
|
+
asset_type_ids=["type-uuid-1", "type-uuid-2"]
|
|
86
|
+
)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Communities
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
# Get a community
|
|
93
|
+
community = connector.community.get_community("community-uuid")
|
|
94
|
+
|
|
95
|
+
# Find communities
|
|
96
|
+
communities = connector.community.find_communities()
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Domains
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
# Get a domain
|
|
103
|
+
domain = connector.domain.get_domain("domain-uuid")
|
|
104
|
+
|
|
105
|
+
# Create a domain
|
|
106
|
+
new_domain = connector.domain.create_domain(
|
|
107
|
+
name="My New Domain",
|
|
108
|
+
community_id="community-uuid"
|
|
109
|
+
)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Users
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
# Get user by username
|
|
116
|
+
user_id = connector.user.get_user_by_username("username")
|
|
117
|
+
|
|
118
|
+
# Create a new user
|
|
119
|
+
new_user = connector.user.create_user(
|
|
120
|
+
username="newuser",
|
|
121
|
+
email_address="newuser@example.com"
|
|
122
|
+
)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Complete Documentation
|
|
126
|
+
|
|
127
|
+
For comprehensive API documentation and examples, see the full README with all available methods for:
|
|
128
|
+
- Asset management (CRUD operations, attributes, activities)
|
|
129
|
+
- Community and Domain operations
|
|
130
|
+
- User management
|
|
131
|
+
- Responsibility assignments
|
|
132
|
+
- Workflow operations
|
|
133
|
+
- Comment management
|
|
134
|
+
- Metadata retrieval
|
|
135
|
+
- Utility functions for bulk operations
|
|
136
|
+
|
|
137
|
+
## Error Handling
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
from collibra_connector.api.Exceptions import (
|
|
141
|
+
CollibraAPIError,
|
|
142
|
+
UnauthorizedError,
|
|
143
|
+
NotFoundError
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
try:
|
|
147
|
+
asset = connector.asset.get_asset("invalid-uuid")
|
|
148
|
+
except NotFoundError:
|
|
149
|
+
print("Asset not found")
|
|
150
|
+
except CollibraAPIError as e:
|
|
151
|
+
print(f"API error: {e}")
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Requirements
|
|
155
|
+
|
|
156
|
+
- Python 3.8+
|
|
157
|
+
- requests >= 2.20.0
|