collibra-connector 1.0.19__py3-none-any.whl → 1.1.1__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 +284 -4
- collibra_connector/api/Asset.py +301 -3
- collibra_connector/api/Attribute.py +204 -0
- collibra_connector/api/Base.py +2 -2
- collibra_connector/api/Relation.py +216 -0
- collibra_connector/api/Responsibility.py +5 -5
- collibra_connector/api/Search.py +102 -0
- collibra_connector/api/Workflow.py +50 -16
- collibra_connector/api/__init__.py +23 -13
- collibra_connector/async_connector.py +930 -0
- collibra_connector/cli.py +597 -0
- collibra_connector/connector.py +270 -48
- collibra_connector/helpers.py +845 -0
- collibra_connector/lineage.py +716 -0
- collibra_connector/models.py +897 -0
- collibra_connector/py.typed +0 -0
- collibra_connector/telemetry.py +576 -0
- collibra_connector/testing.py +806 -0
- collibra_connector-1.1.1.dist-info/METADATA +540 -0
- collibra_connector-1.1.1.dist-info/RECORD +32 -0
- {collibra_connector-1.0.19.dist-info → collibra_connector-1.1.1.dist-info}/WHEEL +1 -1
- collibra_connector-1.1.1.dist-info/entry_points.txt +2 -0
- collibra_connector-1.0.19.dist-info/METADATA +0 -157
- collibra_connector-1.0.19.dist-info/RECORD +0 -21
- {collibra_connector-1.0.19.dist-info → collibra_connector-1.1.1.dist-info}/licenses/LICENSE +0 -0
- {collibra_connector-1.0.19.dist-info → collibra_connector-1.1.1.dist-info}/top_level.txt +0 -0
collibra_connector/connector.py
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Collibra Connector - Main connector class for Collibra API.
|
|
3
|
+
|
|
4
|
+
This module provides the CollibraConnector class which serves as the main
|
|
5
|
+
entry point for interacting with the Collibra Data Governance Center API.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
1
9
|
import logging
|
|
10
|
+
import time
|
|
11
|
+
from typing import Any, Dict, Optional, TYPE_CHECKING
|
|
12
|
+
|
|
2
13
|
import requests
|
|
3
14
|
from requests.auth import HTTPBasicAuth
|
|
4
15
|
|
|
5
16
|
from .api import (
|
|
6
17
|
Asset,
|
|
18
|
+
Attribute,
|
|
7
19
|
Community,
|
|
8
20
|
Domain,
|
|
9
21
|
User,
|
|
@@ -13,77 +25,287 @@ from .api import (
|
|
|
13
25
|
Comment,
|
|
14
26
|
Relation,
|
|
15
27
|
OutputModule,
|
|
16
|
-
Utils
|
|
28
|
+
Utils,
|
|
29
|
+
Search
|
|
17
30
|
)
|
|
18
31
|
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
from requests.auth import AuthBase
|
|
34
|
+
|
|
19
35
|
|
|
20
|
-
class CollibraConnector
|
|
36
|
+
class CollibraConnector:
|
|
21
37
|
"""
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
38
|
+
Main connector class for interacting with the Collibra API.
|
|
39
|
+
|
|
40
|
+
This class provides a unified interface to connect to and interact with
|
|
41
|
+
the Collibra Data Governance Center API. It handles authentication,
|
|
42
|
+
connection management, and provides access to all API modules.
|
|
43
|
+
|
|
44
|
+
Attributes:
|
|
45
|
+
asset: Asset API operations
|
|
46
|
+
community: Community API operations
|
|
47
|
+
domain: Domain API operations
|
|
48
|
+
user: User API operations
|
|
49
|
+
responsibility: Responsibility API operations
|
|
50
|
+
workflow: Workflow API operations
|
|
51
|
+
metadata: Metadata API operations
|
|
52
|
+
comment: Comment API operations
|
|
53
|
+
relation: Relation API operations
|
|
54
|
+
output_module: Output Module API operations
|
|
55
|
+
utils: Utility operations
|
|
56
|
+
|
|
57
|
+
Example:
|
|
58
|
+
>>> connector = CollibraConnector(
|
|
59
|
+
... api="https://your-collibra-instance.com",
|
|
60
|
+
... username="your-username",
|
|
61
|
+
... password="your-password"
|
|
62
|
+
... )
|
|
63
|
+
>>> if connector.test_connection():
|
|
64
|
+
... assets = connector.asset.find_assets()
|
|
65
|
+
|
|
66
|
+
# Using as context manager:
|
|
67
|
+
>>> with CollibraConnector(api="...", username="...", password="...") as conn:
|
|
68
|
+
... assets = conn.asset.find_assets()
|
|
25
69
|
"""
|
|
26
70
|
|
|
27
|
-
|
|
71
|
+
DEFAULT_TIMEOUT: int = 30
|
|
72
|
+
DEFAULT_MAX_RETRIES: int = 3
|
|
73
|
+
DEFAULT_RETRY_DELAY: float = 1.0
|
|
74
|
+
RETRYABLE_STATUS_CODES: tuple = (429, 500, 502, 503, 504)
|
|
75
|
+
|
|
76
|
+
def __init__(
|
|
77
|
+
self,
|
|
78
|
+
api: Optional[str] = None,
|
|
79
|
+
username: Optional[str] = None,
|
|
80
|
+
password: Optional[str] = None,
|
|
81
|
+
timeout: int = DEFAULT_TIMEOUT,
|
|
82
|
+
max_retries: int = DEFAULT_MAX_RETRIES,
|
|
83
|
+
retry_delay: float = DEFAULT_RETRY_DELAY,
|
|
84
|
+
**kwargs: Any
|
|
85
|
+
) -> None:
|
|
28
86
|
"""
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
87
|
+
Initialize the CollibraConnector with API URL and authentication credentials.
|
|
88
|
+
|
|
89
|
+
Credentials can be provided as arguments or via environment variables:
|
|
90
|
+
COLLIBRA_URL, COLLIBRA_USERNAME, COLLIBRA_PASSWORD.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
api: The base API URL for Collibra (e.g., 'https://your-instance.collibra.com').
|
|
94
|
+
username: The username for authentication.
|
|
95
|
+
password: The password for authentication.
|
|
96
|
+
timeout: Request timeout in seconds. Defaults to 30.
|
|
97
|
+
max_retries: Maximum number of retry attempts for failed requests. Defaults to 3.
|
|
98
|
+
retry_delay: Base delay between retries in seconds (uses exponential backoff). Defaults to 1.0.
|
|
99
|
+
**kwargs: Additional keyword arguments.
|
|
100
|
+
- uuids (bool): If True, fetches all UUIDs on initialization.
|
|
101
|
+
|
|
102
|
+
Raises:
|
|
103
|
+
ValueError: If api, username, or password is empty and not in env vars.
|
|
33
104
|
"""
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
105
|
+
import os
|
|
106
|
+
|
|
107
|
+
# Load from env vars if not provided (None means not provided, "" means empty)
|
|
108
|
+
if api is None:
|
|
109
|
+
api = os.environ.get("COLLIBRA_URL")
|
|
110
|
+
if username is None:
|
|
111
|
+
username = os.environ.get("COLLIBRA_USERNAME")
|
|
112
|
+
if password is None:
|
|
113
|
+
password = os.environ.get("COLLIBRA_PASSWORD")
|
|
114
|
+
|
|
115
|
+
if not api or not api.strip():
|
|
116
|
+
raise ValueError("API URL cannot be empty")
|
|
117
|
+
if not username or not username.strip():
|
|
118
|
+
raise ValueError("Username cannot be empty")
|
|
119
|
+
if not password or not password.strip():
|
|
120
|
+
raise ValueError("Password cannot be empty")
|
|
121
|
+
|
|
122
|
+
self.__auth: AuthBase = HTTPBasicAuth(username, password)
|
|
123
|
+
self.__api: str = api.rstrip("/") + "/rest/2.0"
|
|
124
|
+
self.__base_url: str = api.rstrip("/")
|
|
125
|
+
self.__timeout: int = timeout
|
|
126
|
+
self.__max_retries: int = max_retries
|
|
127
|
+
self.__retry_delay: float = retry_delay
|
|
128
|
+
self.__session: Optional[requests.Session] = None
|
|
38
129
|
|
|
39
130
|
# Initialize all API classes
|
|
40
|
-
self.asset = Asset(self)
|
|
41
|
-
self.
|
|
42
|
-
self.
|
|
43
|
-
self.
|
|
44
|
-
self.
|
|
45
|
-
self.
|
|
46
|
-
self.
|
|
47
|
-
self.
|
|
48
|
-
self.
|
|
49
|
-
self.
|
|
50
|
-
self.
|
|
51
|
-
|
|
52
|
-
self.
|
|
131
|
+
self.asset: Asset = Asset(self)
|
|
132
|
+
self.attribute: Attribute = Attribute(self)
|
|
133
|
+
self.community: Community = Community(self)
|
|
134
|
+
self.domain: Domain = Domain(self)
|
|
135
|
+
self.user: User = User(self)
|
|
136
|
+
self.responsibility: Responsibility = Responsibility(self)
|
|
137
|
+
self.workflow: Workflow = Workflow(self)
|
|
138
|
+
self.metadata: Metadata = Metadata(self)
|
|
139
|
+
self.comment: Comment = Comment(self)
|
|
140
|
+
self.relation: Relation = Relation(self)
|
|
141
|
+
self.output_module: OutputModule = OutputModule(self)
|
|
142
|
+
self.utils: Utils = Utils(self)
|
|
143
|
+
self.search: Search = Search(self)
|
|
144
|
+
|
|
145
|
+
# Initialize Logger without basicConfig
|
|
146
|
+
self.logger: logging.Logger = logging.getLogger(__name__)
|
|
147
|
+
self.logger.addHandler(logging.NullHandler())
|
|
148
|
+
|
|
149
|
+
self.uuids: Dict[str, Dict[str, str]] = {}
|
|
53
150
|
if kwargs.get('uuids'):
|
|
54
|
-
self.uuids = self.utils.get_uuids()
|
|
151
|
+
self.uuids = self.utils.get_uuids() or {}
|
|
55
152
|
|
|
56
|
-
|
|
57
|
-
|
|
153
|
+
def __enter__(self) -> "CollibraConnector":
|
|
154
|
+
"""Enter context manager, creating a session for connection pooling."""
|
|
155
|
+
self.__session = requests.Session()
|
|
156
|
+
self.__session.auth = self.__auth
|
|
157
|
+
self.__session.headers.update({
|
|
158
|
+
"Content-Type": "application/json",
|
|
159
|
+
"Accept": "application/json"
|
|
160
|
+
})
|
|
161
|
+
return self
|
|
58
162
|
|
|
59
|
-
def
|
|
60
|
-
|
|
163
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
164
|
+
"""Exit context manager, closing the session."""
|
|
165
|
+
if self.__session:
|
|
166
|
+
self.__session.close()
|
|
167
|
+
self.__session = None
|
|
61
168
|
|
|
62
|
-
def
|
|
63
|
-
"""
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
)
|
|
70
|
-
return response.status_code == 200
|
|
71
|
-
except Exception as e:
|
|
72
|
-
self.logger.error(f"Connection test failed: {e}")
|
|
73
|
-
return False
|
|
169
|
+
def __repr__(self) -> str:
|
|
170
|
+
"""Return string representation of the connector."""
|
|
171
|
+
return f"CollibraConnector(api={self.__base_url})"
|
|
172
|
+
|
|
173
|
+
def __str__(self) -> str:
|
|
174
|
+
"""Return user-friendly string representation."""
|
|
175
|
+
return f"CollibraConnector connected to {self.__base_url}"
|
|
74
176
|
|
|
75
177
|
@property
|
|
76
|
-
def api(self):
|
|
178
|
+
def api(self) -> str:
|
|
179
|
+
"""Get the full API URL including the REST version path."""
|
|
77
180
|
return self.__api
|
|
78
181
|
|
|
79
182
|
@property
|
|
80
|
-
def auth(self):
|
|
183
|
+
def auth(self) -> "AuthBase":
|
|
184
|
+
"""Get the authentication object."""
|
|
81
185
|
return self.__auth
|
|
82
186
|
|
|
83
187
|
@property
|
|
84
|
-
def base_url(self):
|
|
188
|
+
def base_url(self) -> str:
|
|
189
|
+
"""Get the base URL without the REST version path."""
|
|
85
190
|
return self.__base_url
|
|
86
191
|
|
|
87
192
|
@property
|
|
88
|
-
def timeout(self):
|
|
193
|
+
def timeout(self) -> int:
|
|
194
|
+
"""Get the request timeout in seconds."""
|
|
89
195
|
return self.__timeout
|
|
196
|
+
|
|
197
|
+
@property
|
|
198
|
+
def max_retries(self) -> int:
|
|
199
|
+
"""Get the maximum number of retry attempts."""
|
|
200
|
+
return self.__max_retries
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def retry_delay(self) -> float:
|
|
204
|
+
"""Get the base retry delay in seconds."""
|
|
205
|
+
return self.__retry_delay
|
|
206
|
+
|
|
207
|
+
@property
|
|
208
|
+
def session(self) -> Optional[requests.Session]:
|
|
209
|
+
"""Get the current session (if using context manager)."""
|
|
210
|
+
return self.__session
|
|
211
|
+
|
|
212
|
+
def test_connection(self) -> bool:
|
|
213
|
+
"""
|
|
214
|
+
Test the connection to the Collibra API.
|
|
215
|
+
|
|
216
|
+
Makes a request to verify that the credentials are valid and
|
|
217
|
+
the API is reachable.
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
True if connection is successful, False otherwise.
|
|
221
|
+
|
|
222
|
+
Example:
|
|
223
|
+
>>> connector = CollibraConnector(api="...", username="...", password="...")
|
|
224
|
+
>>> if connector.test_connection():
|
|
225
|
+
... print("Connected successfully!")
|
|
226
|
+
"""
|
|
227
|
+
try:
|
|
228
|
+
response = self._make_request(
|
|
229
|
+
method="GET",
|
|
230
|
+
url=f"{self.__api}/auth/sessions/current"
|
|
231
|
+
)
|
|
232
|
+
return response.status_code == 200
|
|
233
|
+
except Exception as e:
|
|
234
|
+
self.logger.error(f"Connection test failed: {e}")
|
|
235
|
+
return False
|
|
236
|
+
|
|
237
|
+
def _make_request(
|
|
238
|
+
self,
|
|
239
|
+
method: str,
|
|
240
|
+
url: str,
|
|
241
|
+
**kwargs: Any
|
|
242
|
+
) -> requests.Response:
|
|
243
|
+
"""
|
|
244
|
+
Make an HTTP request with automatic retry logic.
|
|
245
|
+
|
|
246
|
+
This method handles retries with exponential backoff for transient errors.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
method: HTTP method (GET, POST, PUT, PATCH, DELETE).
|
|
250
|
+
url: The URL to make the request to.
|
|
251
|
+
**kwargs: Additional arguments to pass to the request.
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
The response object from the request.
|
|
255
|
+
|
|
256
|
+
Raises:
|
|
257
|
+
requests.RequestException: If all retry attempts fail.
|
|
258
|
+
"""
|
|
259
|
+
kwargs.setdefault("timeout", self.__timeout)
|
|
260
|
+
kwargs.setdefault("auth", self.__auth)
|
|
261
|
+
|
|
262
|
+
request_func = self.__session.request if self.__session else requests.request
|
|
263
|
+
last_exception: Optional[Exception] = None
|
|
264
|
+
|
|
265
|
+
for attempt in range(self.__max_retries):
|
|
266
|
+
try:
|
|
267
|
+
response = request_func(method, url, **kwargs)
|
|
268
|
+
|
|
269
|
+
# Don't retry on success or client errors (except rate limiting)
|
|
270
|
+
if response.status_code < 500 and response.status_code != 429:
|
|
271
|
+
return response
|
|
272
|
+
|
|
273
|
+
# Retry on server errors and rate limiting
|
|
274
|
+
if response.status_code in self.RETRYABLE_STATUS_CODES:
|
|
275
|
+
if attempt < self.__max_retries - 1:
|
|
276
|
+
delay = self.__retry_delay * (2 ** attempt)
|
|
277
|
+
self.logger.warning(
|
|
278
|
+
f"Request failed with status {response.status_code}, "
|
|
279
|
+
f"retrying in {delay:.1f}s (attempt {attempt + 1}/{self.__max_retries})"
|
|
280
|
+
)
|
|
281
|
+
time.sleep(delay)
|
|
282
|
+
continue
|
|
283
|
+
|
|
284
|
+
return response
|
|
285
|
+
|
|
286
|
+
except (requests.ConnectionError, requests.Timeout) as e:
|
|
287
|
+
last_exception = e
|
|
288
|
+
if attempt < self.__max_retries - 1:
|
|
289
|
+
delay = self.__retry_delay * (2 ** attempt)
|
|
290
|
+
self.logger.warning(
|
|
291
|
+
f"Request failed with {type(e).__name__}, "
|
|
292
|
+
f"retrying in {delay:.1f}s (attempt {attempt + 1}/{self.__max_retries})"
|
|
293
|
+
)
|
|
294
|
+
time.sleep(delay)
|
|
295
|
+
else:
|
|
296
|
+
raise
|
|
297
|
+
|
|
298
|
+
# This should not be reached, but just in case
|
|
299
|
+
if last_exception:
|
|
300
|
+
raise last_exception
|
|
301
|
+
raise requests.RequestException("Request failed after all retries")
|
|
302
|
+
|
|
303
|
+
def get_version(self) -> str:
|
|
304
|
+
"""
|
|
305
|
+
Get the version of this connector library.
|
|
306
|
+
|
|
307
|
+
Returns:
|
|
308
|
+
The version string of the collibra-connector package.
|
|
309
|
+
"""
|
|
310
|
+
from . import __version__
|
|
311
|
+
return __version__
|