pvw-cli 1.0.4__py3-none-any.whl → 1.0.8__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.
Potentially problematic release.
This version of pvw-cli might be problematic. Click here for more details.
- purviewcli/__init__.py +2 -2
- purviewcli/cli/__init__.py +2 -2
- purviewcli/cli/account.py +10 -10
- purviewcli/cli/cli.py +11 -13
- purviewcli/cli/collections.py +369 -6
- purviewcli/cli/entity.py +470 -4
- purviewcli/cli/types.py +2 -2
- purviewcli/cli/unified_catalog.py +766 -0
- purviewcli/client/_search.py +29 -8
- purviewcli/client/_unified_catalog.py +258 -307
- purviewcli/client/endpoint.py +13 -1
- purviewcli/client/sync_client.py +70 -13
- {pvw_cli-1.0.4.dist-info → pvw_cli-1.0.8.dist-info}/METADATA +93 -34
- {pvw_cli-1.0.4.dist-info → pvw_cli-1.0.8.dist-info}/RECORD +17 -18
- {pvw_cli-1.0.4.dist-info → pvw_cli-1.0.8.dist-info}/WHEEL +1 -1
- purviewcli/cli/data_product.py +0 -278
- purviewcli/client/_data_product.py +0 -168
- {pvw_cli-1.0.4.dist-info → pvw_cli-1.0.8.dist-info}/entry_points.txt +0 -0
- {pvw_cli-1.0.4.dist-info → pvw_cli-1.0.8.dist-info}/top_level.txt +0 -0
purviewcli/client/_search.py
CHANGED
|
@@ -33,27 +33,48 @@ class Search(Endpoint):
|
|
|
33
33
|
self.endpoint = ENDPOINTS["discovery"]["query"]
|
|
34
34
|
self.params = get_api_version_params("datamap")
|
|
35
35
|
|
|
36
|
-
#
|
|
36
|
+
# Check if direct payload is provided
|
|
37
|
+
if args.get("--payload"):
|
|
38
|
+
import json
|
|
39
|
+
self.payload = json.loads(args["--payload"])
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
# Check if payload file is provided
|
|
43
|
+
if args.get("--payloadFile"):
|
|
44
|
+
self.payload = get_json(args, "--payloadFile")
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
# Build search payload from individual parameters
|
|
48
|
+
# Support both '--keywords' and the CLI shorthand '--query'
|
|
49
|
+
keywords = args.get("--keywords") if args.get("--keywords") is not None else args.get("--query")
|
|
50
|
+
if keywords is None:
|
|
51
|
+
keywords = "*"
|
|
52
|
+
|
|
37
53
|
search_request = {
|
|
38
|
-
"keywords":
|
|
54
|
+
"keywords": keywords,
|
|
39
55
|
"limit": args.get("--limit", 50),
|
|
40
56
|
"offset": args.get("--offset", 0),
|
|
41
|
-
"filter": {},
|
|
42
|
-
"facets": []
|
|
43
57
|
}
|
|
44
58
|
|
|
59
|
+
# Only add filter if there are actual filter values
|
|
60
|
+
filter_obj = {}
|
|
61
|
+
|
|
45
62
|
# Add filters if provided
|
|
46
63
|
if args.get("--filter"):
|
|
47
|
-
|
|
64
|
+
filter_obj.update(self._parse_filter(args["--filter"]))
|
|
48
65
|
|
|
49
66
|
if args.get("--entityType"):
|
|
50
|
-
|
|
67
|
+
filter_obj["entityType"] = args["--entityType"]
|
|
51
68
|
|
|
52
69
|
if args.get("--classification"):
|
|
53
|
-
|
|
70
|
+
filter_obj["classification"] = args["--classification"]
|
|
54
71
|
|
|
55
72
|
if args.get("--term"):
|
|
56
|
-
|
|
73
|
+
filter_obj["term"] = args["--term"]
|
|
74
|
+
|
|
75
|
+
# Only include filter if it has content
|
|
76
|
+
if filter_obj:
|
|
77
|
+
search_request["filter"] = filter_obj
|
|
57
78
|
|
|
58
79
|
# Add facets if requested
|
|
59
80
|
if args.get("--facets"):
|
|
@@ -1,318 +1,269 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
from .endpoints import ENDPOINTS, DATAMAP_API_VERSION
|
|
1
|
+
"""
|
|
2
|
+
Microsoft Purview Unified Catalog API Client
|
|
3
|
+
Implements comprehensive Unified Catalog functionality
|
|
4
|
+
"""
|
|
6
5
|
|
|
6
|
+
from .endpoint import Endpoint, decorator, get_json, no_api_call_decorator
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
Microsoft Purview Unified Catalog
|
|
11
|
-
Based on the actual Microsoft Purview Unified Catalog API structure
|
|
12
|
-
"""
|
|
8
|
+
|
|
9
|
+
class UnifiedCatalogClient(Endpoint):
|
|
10
|
+
"""Client for Microsoft Purview Unified Catalog API."""
|
|
13
11
|
|
|
14
12
|
def __init__(self):
|
|
15
|
-
"""Initialize the
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"""List data products with optional filtering"""
|
|
48
|
-
params = {}
|
|
49
|
-
if args.get("--limit"):
|
|
50
|
-
params["$top"] = args["--limit"]
|
|
51
|
-
if args.get("--skip"):
|
|
52
|
-
params["$skip"] = args["--skip"]
|
|
53
|
-
if args.get("--governanceDomain"):
|
|
54
|
-
params["domainId"] = args["--governanceDomain"]
|
|
55
|
-
|
|
56
|
-
return self._make_request("GET", "/dataproducts", params=params)
|
|
57
|
-
|
|
58
|
-
def dataProductCreate(self, args):
|
|
59
|
-
"""Create a new data product"""
|
|
60
|
-
payload = self._get_payload_from_args(args)
|
|
61
|
-
return self._make_request("POST", "/dataproducts", data=payload)
|
|
62
|
-
|
|
63
|
-
def dataProductRead(self, args):
|
|
64
|
-
"""Get a data product by ID"""
|
|
65
|
-
data_product_id = args.get("--dataProductId")
|
|
66
|
-
if not data_product_id:
|
|
67
|
-
return {"status": "error", "message": "dataProductId is required"}
|
|
68
|
-
|
|
69
|
-
endpoint = f"/dataproducts/{data_product_id}"
|
|
70
|
-
return self._make_request("GET", endpoint)
|
|
71
|
-
|
|
72
|
-
def dataProductUpdate(self, args):
|
|
73
|
-
"""Update a data product"""
|
|
74
|
-
data_product_id = args.get("--dataProductId")
|
|
75
|
-
if not data_product_id:
|
|
76
|
-
return {"status": "error", "message": "dataProductId is required"}
|
|
77
|
-
|
|
78
|
-
payload = self._get_payload_from_args(args)
|
|
79
|
-
endpoint = f"/dataproducts/{data_product_id}"
|
|
80
|
-
return self._make_request("PUT", endpoint, data=payload)
|
|
81
|
-
|
|
82
|
-
def dataProductDelete(self, args):
|
|
83
|
-
"""Delete a data product"""
|
|
84
|
-
data_product_id = args.get("--dataProductId")
|
|
85
|
-
if not data_product_id:
|
|
86
|
-
return {"status": "error", "message": "dataProductId is required"}
|
|
87
|
-
|
|
88
|
-
endpoint = f"/dataproducts/{data_product_id}"
|
|
89
|
-
return self._make_request("DELETE", endpoint)
|
|
90
|
-
|
|
91
|
-
# === GLOSSARY OPERATIONS ===
|
|
92
|
-
|
|
93
|
-
def glossaryTermsList(self, args):
|
|
94
|
-
"""List glossary terms"""
|
|
95
|
-
params = {}
|
|
96
|
-
if args.get("--governanceDomain"):
|
|
97
|
-
params["domainId"] = args["--governanceDomain"]
|
|
98
|
-
|
|
99
|
-
return self._make_request("GET", "/terms", params=params)
|
|
100
|
-
|
|
101
|
-
def glossaryTermCreate(self, args):
|
|
102
|
-
"""Create a glossary term"""
|
|
103
|
-
payload = self._get_payload_from_args(args)
|
|
104
|
-
return self._make_request("POST", "/terms", data=payload)
|
|
105
|
-
|
|
106
|
-
def glossaryTermRead(self, args):
|
|
107
|
-
"""Get a glossary term by ID"""
|
|
108
|
-
term_id = args.get("--termId")
|
|
109
|
-
if not term_id:
|
|
110
|
-
return {"status": "error", "message": "termId is required"}
|
|
111
|
-
|
|
112
|
-
endpoint = f"/terms/{term_id}"
|
|
113
|
-
return self._make_request("GET", endpoint)
|
|
114
|
-
|
|
115
|
-
def glossaryTermUpdate(self, args):
|
|
116
|
-
"""Update a glossary term"""
|
|
117
|
-
term_id = args.get("--termId")
|
|
118
|
-
if not term_id:
|
|
119
|
-
return {"status": "error", "message": "termId is required"}
|
|
120
|
-
|
|
121
|
-
payload = self._get_payload_from_args(args)
|
|
122
|
-
endpoint = f"/terms/{term_id}"
|
|
123
|
-
return self._make_request("PUT", endpoint, data=payload)
|
|
124
|
-
|
|
125
|
-
def glossaryTermDelete(self, args):
|
|
126
|
-
"""Delete a glossary term"""
|
|
127
|
-
term_id = args.get("--termId")
|
|
128
|
-
if not term_id:
|
|
129
|
-
return {"status": "error", "message": "termId is required"}
|
|
130
|
-
|
|
131
|
-
endpoint = f"/terms/{term_id}"
|
|
132
|
-
return self._make_request("DELETE", endpoint)
|
|
133
|
-
|
|
134
|
-
# === BUSINESS DOMAIN OPERATIONS ===
|
|
135
|
-
|
|
136
|
-
def businessDomainsList(self, args):
|
|
137
|
-
"""List business domains"""
|
|
138
|
-
return self._make_request("GET", "/businessdomains")
|
|
139
|
-
|
|
140
|
-
def businessDomainCreate(self, args):
|
|
141
|
-
"""Create a business domain"""
|
|
142
|
-
payload = self._get_payload_from_args(args)
|
|
143
|
-
return self._make_request("POST", "/businessdomains", data=payload)
|
|
144
|
-
|
|
145
|
-
def businessDomainRead(self, args):
|
|
146
|
-
"""Get a business domain by ID"""
|
|
147
|
-
domain_id = args.get("--domainId")
|
|
148
|
-
if not domain_id:
|
|
149
|
-
return {"status": "error", "message": "domainId is required"}
|
|
150
|
-
|
|
151
|
-
endpoint = f"/businessdomains/{domain_id}"
|
|
152
|
-
return self._make_request("GET", endpoint)
|
|
153
|
-
|
|
154
|
-
def businessDomainUpdate(self, args):
|
|
155
|
-
"""Update a business domain"""
|
|
156
|
-
domain_id = args.get("--domainId")
|
|
157
|
-
if not domain_id:
|
|
158
|
-
return {"status": "error", "message": "domainId is required"}
|
|
159
|
-
|
|
160
|
-
payload = self._get_payload_from_args(args)
|
|
161
|
-
endpoint = f"/businessdomains/{domain_id}"
|
|
162
|
-
return self._make_request("PUT", endpoint, data=payload)
|
|
163
|
-
|
|
164
|
-
def businessDomainDelete(self, args):
|
|
165
|
-
"""Delete a business domain"""
|
|
166
|
-
domain_id = args.get("--domainId")
|
|
167
|
-
if not domain_id:
|
|
168
|
-
return {"status": "error", "message": "domainId is required"}
|
|
169
|
-
|
|
170
|
-
endpoint = f"/businessdomains/{domain_id}"
|
|
171
|
-
return self._make_request("DELETE", endpoint)
|
|
172
|
-
|
|
173
|
-
# === RELATIONSHIP OPERATIONS ===
|
|
174
|
-
|
|
175
|
-
def relationshipCreate(self, args):
|
|
176
|
-
"""Create a relationship between entities"""
|
|
177
|
-
entity_type = args.get("--entityType")
|
|
178
|
-
entity_id = args.get("--entityId")
|
|
179
|
-
|
|
180
|
-
if not entity_type or not entity_id:
|
|
181
|
-
return {"status": "error", "message": "entityType and entityId are required"}
|
|
182
|
-
|
|
183
|
-
endpoint_map = {
|
|
184
|
-
"DataProduct": "dataproducts",
|
|
185
|
-
"Term": "terms",
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if entity_type not in endpoint_map:
|
|
189
|
-
return {"status": "error", "message": f"Unsupported entity type: {entity_type}"}
|
|
190
|
-
|
|
191
|
-
endpoint = f"/{endpoint_map[entity_type]}/{entity_id}/relationships"
|
|
192
|
-
payload = self._get_payload_from_args(args)
|
|
193
|
-
params = {"entityType": entity_type}
|
|
194
|
-
|
|
195
|
-
return self._make_request("POST", endpoint, data=payload, params=params)
|
|
196
|
-
|
|
197
|
-
def relationshipDelete(self, args):
|
|
198
|
-
"""Delete a relationship between entities"""
|
|
199
|
-
entity_type = args.get("--entityType")
|
|
200
|
-
entity_id = args.get("--entityId")
|
|
201
|
-
target_entity_id = args.get("--targetEntityId")
|
|
202
|
-
relationship_type = args.get("--relationshipType")
|
|
203
|
-
|
|
204
|
-
if not all([entity_type, entity_id, target_entity_id, relationship_type]):
|
|
205
|
-
return {"status": "error", "message": "entityType, entityId, targetEntityId, and relationshipType are required"}
|
|
206
|
-
|
|
207
|
-
endpoint_map = {
|
|
208
|
-
"DataProduct": "dataproducts",
|
|
209
|
-
"Term": "terms",
|
|
13
|
+
"""Initialize the Unified Catalog client."""
|
|
14
|
+
Endpoint.__init__(self)
|
|
15
|
+
self.app = "datagovernance" # Use datagovernance app for UC endpoints
|
|
16
|
+
|
|
17
|
+
# ========================================
|
|
18
|
+
# GOVERNANCE DOMAINS
|
|
19
|
+
# ========================================
|
|
20
|
+
@decorator
|
|
21
|
+
def get_governance_domains(self, args):
|
|
22
|
+
"""Get all governance domains."""
|
|
23
|
+
self.method = "GET"
|
|
24
|
+
self.endpoint = "/datagovernance/catalog/businessdomains"
|
|
25
|
+
self.params = {}
|
|
26
|
+
|
|
27
|
+
@decorator
|
|
28
|
+
def get_governance_domain_by_id(self, args):
|
|
29
|
+
"""Get a governance domain by ID."""
|
|
30
|
+
domain_id = args.get("--domain-id", [""])[0]
|
|
31
|
+
self.method = "GET"
|
|
32
|
+
self.endpoint = f"/datagovernance/catalog/businessdomains/{domain_id}"
|
|
33
|
+
self.params = {}
|
|
34
|
+
|
|
35
|
+
@decorator
|
|
36
|
+
def create_governance_domain(self, args):
|
|
37
|
+
"""Create a new governance domain."""
|
|
38
|
+
self.method = "POST"
|
|
39
|
+
self.endpoint = "/datagovernance/catalog/businessdomains"
|
|
40
|
+
self.payload = get_json(args, "--payloadFile") or {
|
|
41
|
+
"name": args.get("--name", [""])[0],
|
|
42
|
+
"description": args.get("--description", [""])[0],
|
|
43
|
+
"type": args.get("--type", ["FunctionalUnit"])[0],
|
|
44
|
+
"status": args.get("--status", ["Draft"])[0],
|
|
210
45
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
"
|
|
46
|
+
|
|
47
|
+
@decorator
|
|
48
|
+
def update_governance_domain(self, args):
|
|
49
|
+
"""Update a governance domain."""
|
|
50
|
+
domain_id = args.get("--domain-id", [""])[0]
|
|
51
|
+
self.method = "PUT"
|
|
52
|
+
self.endpoint = f"/datagovernance/catalog/businessdomains/{domain_id}"
|
|
53
|
+
self.payload = get_json(args, "--payloadFile") or {
|
|
54
|
+
"name": args.get("--name", [""])[0],
|
|
55
|
+
"description": args.get("--description", [""])[0],
|
|
56
|
+
"type": args.get("--type", [""])[0],
|
|
57
|
+
"status": args.get("--status", [""])[0],
|
|
220
58
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
if args.get("--
|
|
242
|
-
|
|
243
|
-
if args.get("--type"):
|
|
244
|
-
payload["type"] = args["--type"]
|
|
245
|
-
if args.get("--businessUse"):
|
|
246
|
-
payload["businessUse"] = args["--businessUse"]
|
|
59
|
+
|
|
60
|
+
@decorator
|
|
61
|
+
def delete_governance_domain(self, args):
|
|
62
|
+
"""Delete a governance domain."""
|
|
63
|
+
domain_id = args.get("--domain-id", [""])[0]
|
|
64
|
+
self.method = "DELETE"
|
|
65
|
+
self.endpoint = f"/datagovernance/catalog/businessdomains/{domain_id}"
|
|
66
|
+
self.params = {}
|
|
67
|
+
|
|
68
|
+
# ========================================
|
|
69
|
+
# DATA PRODUCTS
|
|
70
|
+
# ========================================
|
|
71
|
+
@decorator
|
|
72
|
+
def get_data_products(self, args):
|
|
73
|
+
"""Get all data products."""
|
|
74
|
+
self.method = "GET"
|
|
75
|
+
self.endpoint = "/datagovernance/dataProducts"
|
|
76
|
+
self.params = {}
|
|
77
|
+
|
|
78
|
+
# Add optional filters
|
|
79
|
+
if args.get("--domain-id"):
|
|
80
|
+
self.params["domainId"] = args["--domain-id"][0]
|
|
247
81
|
if args.get("--status"):
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
"
|
|
267
|
-
"
|
|
268
|
-
"--governanceDomain": domain_guid,
|
|
269
|
-
"--type": "Dataset", # Default type
|
|
270
|
-
"--status": "Draft" # Default status
|
|
82
|
+
self.params["status"] = args["--status"][0]
|
|
83
|
+
|
|
84
|
+
@decorator
|
|
85
|
+
def get_data_product_by_id(self, args):
|
|
86
|
+
"""Get a data product by ID."""
|
|
87
|
+
product_id = args.get("--product-id", [""])[0]
|
|
88
|
+
self.method = "GET"
|
|
89
|
+
self.endpoint = f"/datagovernance/dataProducts/{product_id}"
|
|
90
|
+
self.params = {}
|
|
91
|
+
|
|
92
|
+
@decorator
|
|
93
|
+
def create_data_product(self, args):
|
|
94
|
+
"""Create a new data product."""
|
|
95
|
+
self.method = "POST"
|
|
96
|
+
self.endpoint = "/datagovernance/dataProducts"
|
|
97
|
+
self.payload = get_json(args, "--payloadFile") or {
|
|
98
|
+
"name": args.get("--name", [""])[0],
|
|
99
|
+
"description": args.get("--description", [""])[0],
|
|
100
|
+
"domainId": args.get("--domain-id", [""])[0],
|
|
101
|
+
"status": args.get("--status", ["Draft"])[0],
|
|
271
102
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
def
|
|
275
|
-
"""
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
def delete_data_product(self, data_product_id):
|
|
286
|
-
"""Delete a data product by ID"""
|
|
287
|
-
args = {"--dataProductId": data_product_id}
|
|
288
|
-
return self.dataProductDelete(args)
|
|
289
|
-
|
|
290
|
-
def list_data_products(self, limit=50, offset=0, domain_id=None):
|
|
291
|
-
"""List data products with pagination"""
|
|
292
|
-
args = {
|
|
293
|
-
"--limit": str(limit),
|
|
294
|
-
"--skip": str(offset)
|
|
103
|
+
|
|
104
|
+
@decorator
|
|
105
|
+
def update_data_product(self, args):
|
|
106
|
+
"""Update a data product."""
|
|
107
|
+
product_id = args.get("--product-id", [""])[0]
|
|
108
|
+
self.method = "PUT"
|
|
109
|
+
self.endpoint = f"/datagovernance/dataProducts/{product_id}"
|
|
110
|
+
self.payload = get_json(args, "--payloadFile") or {
|
|
111
|
+
"name": args.get("--name", [""])[0],
|
|
112
|
+
"description": args.get("--description", [""])[0],
|
|
113
|
+
"domainId": args.get("--domain-id", [""])[0],
|
|
114
|
+
"status": args.get("--status", [""])[0],
|
|
295
115
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
116
|
+
|
|
117
|
+
@decorator
|
|
118
|
+
def delete_data_product(self, args):
|
|
119
|
+
"""Delete a data product."""
|
|
120
|
+
product_id = args.get("--product-id", [""])[0]
|
|
121
|
+
self.method = "DELETE"
|
|
122
|
+
self.endpoint = f"/datagovernance/dataProducts/{product_id}"
|
|
123
|
+
self.params = {}
|
|
124
|
+
|
|
125
|
+
# ========================================
|
|
126
|
+
# GLOSSARY TERMS
|
|
127
|
+
# ========================================
|
|
128
|
+
|
|
129
|
+
@decorator
|
|
130
|
+
def get_terms(self, args):
|
|
131
|
+
"""Get all glossary terms in a governance domain."""
|
|
132
|
+
domain_id = args.get("--governance-domain-id", [""])[0]
|
|
133
|
+
self.method = "GET"
|
|
134
|
+
self.endpoint = f"/datagovernance/catalog/businessdomains/{domain_id}/glossaryterms"
|
|
135
|
+
self.params = {}
|
|
136
|
+
|
|
137
|
+
@decorator
|
|
138
|
+
def get_term_by_id(self, args):
|
|
139
|
+
"""Get a glossary term by ID."""
|
|
140
|
+
term_id = args.get("--term-id", [""])[0]
|
|
141
|
+
self.method = "GET"
|
|
142
|
+
self.endpoint = f"/datagovernance/catalog/glossaryterms/{term_id}"
|
|
143
|
+
self.params = {}
|
|
144
|
+
|
|
145
|
+
@decorator
|
|
146
|
+
def create_term(self, args):
|
|
147
|
+
"""Create a new glossary term."""
|
|
148
|
+
self.method = "POST"
|
|
149
|
+
self.endpoint = "/datagovernance/catalog/glossaryterms"
|
|
150
|
+
|
|
151
|
+
# Build payload
|
|
152
|
+
payload = {
|
|
153
|
+
"name": args.get("--name", [""])[0],
|
|
154
|
+
"description": args.get("--description", [""])[0],
|
|
155
|
+
"governanceDomainId": args.get("--governance-domain-id", [""])[0],
|
|
156
|
+
"status": args.get("--status", ["Draft"])[0],
|
|
307
157
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
args
|
|
313
|
-
"
|
|
314
|
-
|
|
315
|
-
"
|
|
316
|
-
|
|
158
|
+
|
|
159
|
+
# Add optional fields
|
|
160
|
+
if args.get("--acronyms"):
|
|
161
|
+
payload["acronyms"] = args["--acronyms"]
|
|
162
|
+
if args.get("--owner-id"):
|
|
163
|
+
payload["ownerIds"] = args["--owner-id"]
|
|
164
|
+
if args.get("--resource-name") and args.get("--resource-url"):
|
|
165
|
+
payload["resources"] = [
|
|
166
|
+
{"name": args["--resource-name"][0], "url": args["--resource-url"][0]}
|
|
167
|
+
]
|
|
168
|
+
|
|
169
|
+
self.payload = payload
|
|
170
|
+
|
|
171
|
+
# ========================================
|
|
172
|
+
# OBJECTIVES AND KEY RESULTS (OKRs)
|
|
173
|
+
# ========================================
|
|
174
|
+
|
|
175
|
+
@decorator
|
|
176
|
+
def get_objectives(self, args):
|
|
177
|
+
"""Get all objectives in a governance domain."""
|
|
178
|
+
domain_id = args.get("--governance-domain-id", [""])[0]
|
|
179
|
+
self.method = "GET"
|
|
180
|
+
self.endpoint = f"/datagovernance/catalog/businessdomains/{domain_id}/objectives"
|
|
181
|
+
self.params = {}
|
|
182
|
+
|
|
183
|
+
@decorator
|
|
184
|
+
def get_objective_by_id(self, args):
|
|
185
|
+
"""Get an objective by ID."""
|
|
186
|
+
objective_id = args.get("--objective-id", [""])[0]
|
|
187
|
+
self.method = "GET"
|
|
188
|
+
self.endpoint = f"/datagovernance/catalog/objectives/{objective_id}"
|
|
189
|
+
self.params = {}
|
|
190
|
+
|
|
191
|
+
@decorator
|
|
192
|
+
def create_objective(self, args):
|
|
193
|
+
"""Create a new objective."""
|
|
194
|
+
self.method = "POST"
|
|
195
|
+
self.endpoint = "/datagovernance/catalog/objectives"
|
|
196
|
+
|
|
197
|
+
payload = {
|
|
198
|
+
"definition": args.get("--definition", [""])[0],
|
|
199
|
+
"governanceDomainId": args.get("--governance-domain-id", [""])[0],
|
|
200
|
+
"status": args.get("--status", ["Draft"])[0],
|
|
317
201
|
}
|
|
318
|
-
|
|
202
|
+
|
|
203
|
+
if args.get("--owner-id"):
|
|
204
|
+
payload["ownerIds"] = args["--owner-id"]
|
|
205
|
+
if args.get("--target-date"):
|
|
206
|
+
payload["targetDate"] = args["--target-date"][0]
|
|
207
|
+
|
|
208
|
+
self.payload = payload
|
|
209
|
+
|
|
210
|
+
# ========================================
|
|
211
|
+
# CRITICAL DATA ELEMENTS (CDEs)
|
|
212
|
+
# ========================================
|
|
213
|
+
|
|
214
|
+
@decorator
|
|
215
|
+
def get_critical_data_elements(self, args):
|
|
216
|
+
"""Get all critical data elements in a governance domain."""
|
|
217
|
+
domain_id = args.get("--governance-domain-id", [""])[0]
|
|
218
|
+
self.method = "GET"
|
|
219
|
+
self.endpoint = f"/datagovernance/catalog/businessdomains/{domain_id}/criticaldataelements"
|
|
220
|
+
self.params = {}
|
|
221
|
+
|
|
222
|
+
@decorator
|
|
223
|
+
def get_critical_data_element_by_id(self, args):
|
|
224
|
+
"""Get a critical data element by ID."""
|
|
225
|
+
cde_id = args.get("--cde-id", [""])[0]
|
|
226
|
+
self.method = "GET"
|
|
227
|
+
self.endpoint = f"/datagovernance/catalog/criticaldataelements/{cde_id}"
|
|
228
|
+
self.params = {}
|
|
229
|
+
|
|
230
|
+
@decorator
|
|
231
|
+
def create_critical_data_element(self, args):
|
|
232
|
+
"""Create a new critical data element."""
|
|
233
|
+
self.method = "POST"
|
|
234
|
+
self.endpoint = "/datagovernance/catalog/criticaldataelements"
|
|
235
|
+
|
|
236
|
+
payload = {
|
|
237
|
+
"name": args.get("--name", [""])[0],
|
|
238
|
+
"description": args.get("--description", [""])[0],
|
|
239
|
+
"governanceDomainId": args.get("--governance-domain-id", [""])[0],
|
|
240
|
+
"dataType": args.get("--data-type", ["String"])[0],
|
|
241
|
+
"status": args.get("--status", ["Draft"])[0],
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if args.get("--owner-id"):
|
|
245
|
+
payload["ownerIds"] = args["--owner-id"]
|
|
246
|
+
|
|
247
|
+
self.payload = payload
|
|
248
|
+
|
|
249
|
+
# ========================================
|
|
250
|
+
# UTILITY METHODS
|
|
251
|
+
# ========================================
|
|
252
|
+
|
|
253
|
+
@no_api_call_decorator
|
|
254
|
+
def help(self, args):
|
|
255
|
+
"""Display help information for Unified Catalog operations."""
|
|
256
|
+
help_text = """
|
|
257
|
+
Microsoft Purview Unified Catalog Client
|
|
258
|
+
|
|
259
|
+
Available Operations:
|
|
260
|
+
- Governance Domains: list, get, create, update, delete
|
|
261
|
+
- Data Products: list, get, create, update, delete
|
|
262
|
+
- Glossary Terms: list, get, create
|
|
263
|
+
- Objectives (OKRs): list, get, create
|
|
264
|
+
- Critical Data Elements: list, get, create
|
|
265
|
+
|
|
266
|
+
Use --payloadFile to provide JSON payload for create/update operations.
|
|
267
|
+
Use individual flags like --name, --description for simple operations.
|
|
268
|
+
"""
|
|
269
|
+
return {"message": help_text}
|