pvw-cli 1.2.3__py3-none-any.whl → 1.2.5__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 +1 -1
- purviewcli/cli/lineage.py +4 -1
- purviewcli/cli/types.py +333 -0
- purviewcli/cli/unified_catalog.py +1329 -9
- purviewcli/client/_entity.py +74 -17
- purviewcli/client/_lineage.py +206 -44
- purviewcli/client/_types.py +31 -0
- purviewcli/client/_unified_catalog.py +646 -30
- purviewcli/client/endpoints.py +75 -0
- {pvw_cli-1.2.3.dist-info → pvw_cli-1.2.5.dist-info}/METADATA +232 -75
- {pvw_cli-1.2.3.dist-info → pvw_cli-1.2.5.dist-info}/RECORD +14 -14
- {pvw_cli-1.2.3.dist-info → pvw_cli-1.2.5.dist-info}/WHEEL +0 -0
- {pvw_cli-1.2.3.dist-info → pvw_cli-1.2.5.dist-info}/entry_points.txt +0 -0
- {pvw_cli-1.2.3.dist-info → pvw_cli-1.2.5.dist-info}/top_level.txt +0 -0
|
@@ -4,6 +4,7 @@ Implements comprehensive Unified Catalog functionality
|
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
from .endpoint import Endpoint, decorator, get_json, no_api_call_decorator
|
|
7
|
+
from .endpoints import ENDPOINTS, get_api_version_params
|
|
7
8
|
import os
|
|
8
9
|
import json
|
|
9
10
|
|
|
@@ -23,7 +24,7 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
23
24
|
def get_governance_domains(self, args):
|
|
24
25
|
"""Get all governance domains."""
|
|
25
26
|
self.method = "GET"
|
|
26
|
-
self.endpoint = "
|
|
27
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_domains"]
|
|
27
28
|
self.params = {}
|
|
28
29
|
|
|
29
30
|
@decorator
|
|
@@ -31,14 +32,14 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
31
32
|
"""Get a governance domain by ID."""
|
|
32
33
|
domain_id = args.get("--domain-id", [""])[0]
|
|
33
34
|
self.method = "GET"
|
|
34
|
-
self.endpoint =
|
|
35
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_domain"].format(domainId=domain_id)
|
|
35
36
|
self.params = {}
|
|
36
37
|
|
|
37
38
|
@decorator
|
|
38
39
|
def create_governance_domain(self, args):
|
|
39
40
|
"""Create a new governance domain."""
|
|
40
41
|
self.method = "POST"
|
|
41
|
-
self.endpoint = "
|
|
42
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_domains"]
|
|
42
43
|
# Allow payload file to fully control creation; otherwise build payload from flags
|
|
43
44
|
payload = get_json(args, "--payloadFile")
|
|
44
45
|
if not payload:
|
|
@@ -61,7 +62,7 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
61
62
|
"""Update a governance domain."""
|
|
62
63
|
domain_id = args.get("--domain-id", [""])[0]
|
|
63
64
|
self.method = "PUT"
|
|
64
|
-
self.endpoint =
|
|
65
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_domain"].format(domainId=domain_id)
|
|
65
66
|
self.payload = get_json(args, "--payloadFile") or {
|
|
66
67
|
"name": args.get("--name", [""])[0],
|
|
67
68
|
"description": args.get("--description", [""])[0],
|
|
@@ -74,7 +75,7 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
74
75
|
"""Delete a governance domain."""
|
|
75
76
|
domain_id = args.get("--domain-id", [""])[0]
|
|
76
77
|
self.method = "DELETE"
|
|
77
|
-
self.endpoint =
|
|
78
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_domain"].format(domainId=domain_id)
|
|
78
79
|
self.params = {}
|
|
79
80
|
|
|
80
81
|
# ========================================
|
|
@@ -84,7 +85,7 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
84
85
|
def get_data_products(self, args):
|
|
85
86
|
"""Get all data products."""
|
|
86
87
|
self.method = "GET"
|
|
87
|
-
self.endpoint = "
|
|
88
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_data_products"]
|
|
88
89
|
|
|
89
90
|
# Add optional filters
|
|
90
91
|
domain_id = args.get("--governance-domain-id", [""])[0] or args.get("--domain-id", [""])[0]
|
|
@@ -98,14 +99,14 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
98
99
|
"""Get a data product by ID."""
|
|
99
100
|
product_id = args.get("--product-id", [""])[0]
|
|
100
101
|
self.method = "GET"
|
|
101
|
-
self.endpoint =
|
|
102
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_data_product"].format(productId=product_id)
|
|
102
103
|
self.params = {}
|
|
103
104
|
|
|
104
105
|
@decorator
|
|
105
106
|
def create_data_product(self, args):
|
|
106
107
|
"""Create a new data product."""
|
|
107
108
|
self.method = "POST"
|
|
108
|
-
self.endpoint = "
|
|
109
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_data_products"]
|
|
109
110
|
|
|
110
111
|
# Get domain ID
|
|
111
112
|
domain_id = args.get("--governance-domain-id", [""])[0] or args.get("--domain-id", [""])[0]
|
|
@@ -193,7 +194,7 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
193
194
|
|
|
194
195
|
# Now perform the PUT request
|
|
195
196
|
self.method = "PUT"
|
|
196
|
-
self.endpoint =
|
|
197
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_data_product"].format(productId=product_id)
|
|
197
198
|
self.payload = payload
|
|
198
199
|
|
|
199
200
|
@decorator
|
|
@@ -201,9 +202,145 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
201
202
|
"""Delete a data product."""
|
|
202
203
|
product_id = args.get("--product-id", [""])[0]
|
|
203
204
|
self.method = "DELETE"
|
|
204
|
-
self.endpoint =
|
|
205
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_data_product"].format(productId=product_id)
|
|
205
206
|
self.params = {}
|
|
206
207
|
|
|
208
|
+
@decorator
|
|
209
|
+
def create_data_product_relationship(self, args):
|
|
210
|
+
"""Create a relationship for a data product.
|
|
211
|
+
|
|
212
|
+
Creates a relationship between a data product and another entity
|
|
213
|
+
(e.g., critical data column, term, asset).
|
|
214
|
+
|
|
215
|
+
API: POST /datagovernance/catalog/dataproducts/{productId}/relationships
|
|
216
|
+
API Version: 2025-09-15-preview
|
|
217
|
+
"""
|
|
218
|
+
product_id = args.get("--product-id", [""])[0]
|
|
219
|
+
entity_type = args.get("--entity-type", [""])[0] # e.g., "CRITICALDATACOLUMN"
|
|
220
|
+
entity_id = args.get("--entity-id", [""])[0]
|
|
221
|
+
asset_id = args.get("--asset-id", [""])[0] if args.get("--asset-id") else entity_id
|
|
222
|
+
relationship_type = args.get("--relationship-type", ["Related"])[0]
|
|
223
|
+
description = args.get("--description", [""])[0]
|
|
224
|
+
|
|
225
|
+
# Build request body
|
|
226
|
+
payload = {
|
|
227
|
+
"relationship1": {
|
|
228
|
+
"description": description,
|
|
229
|
+
"relationshipType": relationship_type,
|
|
230
|
+
"assetId": asset_id,
|
|
231
|
+
"entityId": entity_id
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
self.method = "POST"
|
|
236
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["create_data_product_relationship"].format(
|
|
237
|
+
productId=product_id
|
|
238
|
+
)
|
|
239
|
+
self.params = {"entityType": entity_type.upper()}
|
|
240
|
+
self.payload = payload
|
|
241
|
+
|
|
242
|
+
@decorator
|
|
243
|
+
def get_data_product_relationships(self, args):
|
|
244
|
+
"""List relationships for a data product.
|
|
245
|
+
|
|
246
|
+
Lists all relationships for a data product, optionally filtered by entity type.
|
|
247
|
+
|
|
248
|
+
API: GET /datagovernance/catalog/dataproducts/{productId}/relationships
|
|
249
|
+
API Version: 2025-09-15-preview
|
|
250
|
+
"""
|
|
251
|
+
product_id = args.get("--product-id", [""])[0]
|
|
252
|
+
entity_type = args.get("--entity-type", [""])[0] if args.get("--entity-type") else None
|
|
253
|
+
|
|
254
|
+
self.method = "GET"
|
|
255
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_data_product_relationships"].format(
|
|
256
|
+
productId=product_id
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
# Entity type is optional filter
|
|
260
|
+
if entity_type:
|
|
261
|
+
self.params = {"entityType": entity_type.upper()}
|
|
262
|
+
else:
|
|
263
|
+
self.params = {}
|
|
264
|
+
|
|
265
|
+
@decorator
|
|
266
|
+
def delete_data_product_relationship(self, args):
|
|
267
|
+
"""Delete a relationship between a data product and an entity.
|
|
268
|
+
|
|
269
|
+
Deletes a specific relationship identified by entity type and entity ID.
|
|
270
|
+
|
|
271
|
+
API: DELETE /datagovernance/catalog/dataproducts/{productId}/relationships
|
|
272
|
+
API Version: 2025-09-15-preview
|
|
273
|
+
"""
|
|
274
|
+
product_id = args.get("--product-id", [""])[0]
|
|
275
|
+
entity_type = args.get("--entity-type", [""])[0]
|
|
276
|
+
entity_id = args.get("--entity-id", [""])[0]
|
|
277
|
+
|
|
278
|
+
self.method = "DELETE"
|
|
279
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["delete_data_product_relationship"].format(
|
|
280
|
+
productId=product_id
|
|
281
|
+
)
|
|
282
|
+
self.params = {
|
|
283
|
+
"entityType": entity_type.upper(),
|
|
284
|
+
"entityId": entity_id
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
@decorator
|
|
288
|
+
def query_data_products(self, args):
|
|
289
|
+
"""Query data products with advanced filters.
|
|
290
|
+
|
|
291
|
+
Supports filtering by domain, owner, status, name keyword, type, and more.
|
|
292
|
+
Includes pagination (skip/top) and sorting (orderBy).
|
|
293
|
+
|
|
294
|
+
API: POST /datagovernance/catalog/dataproducts/query
|
|
295
|
+
API Version: 2025-09-15-preview
|
|
296
|
+
"""
|
|
297
|
+
# Build query payload from args
|
|
298
|
+
payload = {}
|
|
299
|
+
|
|
300
|
+
# IDs and domain filters
|
|
301
|
+
if args.get("--ids"):
|
|
302
|
+
payload["ids"] = args["--ids"]
|
|
303
|
+
if args.get("--domain-ids"):
|
|
304
|
+
payload["domainIds"] = args["--domain-ids"]
|
|
305
|
+
|
|
306
|
+
# Name/keyword search
|
|
307
|
+
if args.get("--name-keyword"):
|
|
308
|
+
payload["nameKeyword"] = args["--name-keyword"][0]
|
|
309
|
+
|
|
310
|
+
# Owner filter
|
|
311
|
+
if args.get("--owners"):
|
|
312
|
+
payload["owners"] = args["--owners"]
|
|
313
|
+
|
|
314
|
+
# Status filters
|
|
315
|
+
if args.get("--status"):
|
|
316
|
+
payload["status"] = args["--status"][0]
|
|
317
|
+
if args.get("--multi-status"):
|
|
318
|
+
payload["multiStatus"] = args["--multi-status"]
|
|
319
|
+
|
|
320
|
+
# Type filters
|
|
321
|
+
if args.get("--type"):
|
|
322
|
+
payload["type"] = args["--type"][0]
|
|
323
|
+
if args.get("--types"):
|
|
324
|
+
payload["types"] = args["--types"]
|
|
325
|
+
|
|
326
|
+
# Pagination
|
|
327
|
+
if args.get("--skip"):
|
|
328
|
+
payload["skip"] = int(args["--skip"][0])
|
|
329
|
+
if args.get("--top"):
|
|
330
|
+
payload["top"] = int(args["--top"][0])
|
|
331
|
+
|
|
332
|
+
# Sorting
|
|
333
|
+
if args.get("--order-by-field"):
|
|
334
|
+
payload["orderby"] = [{
|
|
335
|
+
"field": args["--order-by-field"][0],
|
|
336
|
+
"direction": args.get("--order-by-direction", ["asc"])[0]
|
|
337
|
+
}]
|
|
338
|
+
|
|
339
|
+
self.method = "POST"
|
|
340
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["query_data_products"]
|
|
341
|
+
self.params = {}
|
|
342
|
+
self.payload = payload
|
|
343
|
+
|
|
207
344
|
# ========================================
|
|
208
345
|
# GLOSSARY TERMS
|
|
209
346
|
# ========================================
|
|
@@ -222,11 +359,11 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
222
359
|
|
|
223
360
|
if domain_id:
|
|
224
361
|
# Use Unified Catalog terms API with domainId filter
|
|
225
|
-
self.endpoint = "
|
|
362
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_terms"]
|
|
226
363
|
self.params = {"domainId": domain_id}
|
|
227
364
|
else:
|
|
228
365
|
# List all UC terms
|
|
229
|
-
self.endpoint = "
|
|
366
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_terms"]
|
|
230
367
|
self.params = {}
|
|
231
368
|
|
|
232
369
|
# Keeping old Data Map glossary-based implementation for reference/fallback
|
|
@@ -368,14 +505,14 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
368
505
|
"""Get a Unified Catalog term by ID."""
|
|
369
506
|
term_id = args.get("--term-id", [""])[0]
|
|
370
507
|
self.method = "GET"
|
|
371
|
-
self.endpoint =
|
|
508
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_term"].format(termId=term_id)
|
|
372
509
|
self.params = {}
|
|
373
510
|
|
|
374
511
|
@decorator
|
|
375
512
|
def create_term(self, args):
|
|
376
513
|
"""Create a new Unified Catalog term (Governance Domain term)."""
|
|
377
514
|
self.method = "POST"
|
|
378
|
-
self.endpoint = "
|
|
515
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_terms"]
|
|
379
516
|
|
|
380
517
|
# Build Unified Catalog term payload
|
|
381
518
|
domain_id = args.get("--governance-domain-id", [""])[0]
|
|
@@ -530,9 +667,64 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
530
667
|
"""Delete a Unified Catalog term."""
|
|
531
668
|
term_id = args.get("--term-id", [""])[0]
|
|
532
669
|
self.method = "DELETE"
|
|
533
|
-
self.endpoint =
|
|
670
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_term"].format(termId=term_id)
|
|
534
671
|
self.params = {}
|
|
535
672
|
|
|
673
|
+
@decorator
|
|
674
|
+
def query_terms(self, args):
|
|
675
|
+
"""Query terms with advanced filters.
|
|
676
|
+
|
|
677
|
+
Supports filtering by domain, owner, status, name keyword, acronyms, and more.
|
|
678
|
+
Includes pagination (skip/top) and sorting (orderBy).
|
|
679
|
+
|
|
680
|
+
API: POST /datagovernance/catalog/terms/query
|
|
681
|
+
API Version: 2025-09-15-preview
|
|
682
|
+
"""
|
|
683
|
+
# Build query payload from args
|
|
684
|
+
payload = {}
|
|
685
|
+
|
|
686
|
+
# IDs and domain filters
|
|
687
|
+
if args.get("--ids"):
|
|
688
|
+
payload["ids"] = args["--ids"]
|
|
689
|
+
if args.get("--domain-ids"):
|
|
690
|
+
payload["domainIds"] = args["--domain-ids"]
|
|
691
|
+
|
|
692
|
+
# Name/keyword search
|
|
693
|
+
if args.get("--name-keyword"):
|
|
694
|
+
payload["nameKeyword"] = args["--name-keyword"][0]
|
|
695
|
+
|
|
696
|
+
# Acronym filter (terms-specific)
|
|
697
|
+
if args.get("--acronyms"):
|
|
698
|
+
payload["acronyms"] = args["--acronyms"]
|
|
699
|
+
|
|
700
|
+
# Owner filter
|
|
701
|
+
if args.get("--owners"):
|
|
702
|
+
payload["owners"] = args["--owners"]
|
|
703
|
+
|
|
704
|
+
# Status filters
|
|
705
|
+
if args.get("--status"):
|
|
706
|
+
payload["status"] = args["--status"][0]
|
|
707
|
+
if args.get("--multi-status"):
|
|
708
|
+
payload["multiStatus"] = args["--multi-status"]
|
|
709
|
+
|
|
710
|
+
# Pagination
|
|
711
|
+
if args.get("--skip"):
|
|
712
|
+
payload["skip"] = int(args["--skip"][0])
|
|
713
|
+
if args.get("--top"):
|
|
714
|
+
payload["top"] = int(args["--top"][0])
|
|
715
|
+
|
|
716
|
+
# Sorting
|
|
717
|
+
if args.get("--order-by-field"):
|
|
718
|
+
payload["orderby"] = [{
|
|
719
|
+
"field": args["--order-by-field"][0],
|
|
720
|
+
"direction": args.get("--order-by-direction", ["asc"])[0]
|
|
721
|
+
}]
|
|
722
|
+
|
|
723
|
+
self.method = "POST"
|
|
724
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["query_terms"]
|
|
725
|
+
self.params = {}
|
|
726
|
+
self.payload = payload
|
|
727
|
+
|
|
536
728
|
def _get_or_create_glossary_for_domain(self, domain_id):
|
|
537
729
|
"""Get or create a default glossary for the domain."""
|
|
538
730
|
# Improved implementation:
|
|
@@ -612,7 +804,7 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
612
804
|
"""Get all objectives in a governance domain."""
|
|
613
805
|
domain_id = args.get("--governance-domain-id", [""])[0]
|
|
614
806
|
self.method = "GET"
|
|
615
|
-
self.endpoint = "
|
|
807
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_objectives"]
|
|
616
808
|
self.params = {"domainId": domain_id} if domain_id else {}
|
|
617
809
|
|
|
618
810
|
@decorator
|
|
@@ -620,14 +812,14 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
620
812
|
"""Get an objective by ID."""
|
|
621
813
|
objective_id = args.get("--objective-id", [""])[0]
|
|
622
814
|
self.method = "GET"
|
|
623
|
-
self.endpoint =
|
|
815
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_objective"].format(objectiveId=objective_id)
|
|
624
816
|
self.params = {}
|
|
625
817
|
|
|
626
818
|
@decorator
|
|
627
819
|
def create_objective(self, args):
|
|
628
820
|
"""Create a new objective."""
|
|
629
821
|
self.method = "POST"
|
|
630
|
-
self.endpoint = "
|
|
822
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_objectives"]
|
|
631
823
|
|
|
632
824
|
domain_id = args.get("--governance-domain-id", [""])[0]
|
|
633
825
|
definition = args.get("--definition", [""])[0]
|
|
@@ -658,7 +850,7 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
658
850
|
"""Update an existing objective."""
|
|
659
851
|
objective_id = args.get("--objective-id", [""])[0]
|
|
660
852
|
self.method = "PUT"
|
|
661
|
-
self.endpoint =
|
|
853
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_objective"].format(objectiveId=objective_id)
|
|
662
854
|
|
|
663
855
|
domain_id = args.get("--governance-domain-id", [""])[0]
|
|
664
856
|
definition = args.get("--definition", [""])[0]
|
|
@@ -690,8 +882,59 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
690
882
|
"""Delete an objective."""
|
|
691
883
|
objective_id = args.get("--objective-id", [""])[0]
|
|
692
884
|
self.method = "DELETE"
|
|
693
|
-
self.endpoint =
|
|
885
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_objective"].format(objectiveId=objective_id)
|
|
886
|
+
self.params = {}
|
|
887
|
+
|
|
888
|
+
@decorator
|
|
889
|
+
def query_objectives(self, args):
|
|
890
|
+
"""Query objectives with advanced filters.
|
|
891
|
+
|
|
892
|
+
Supports filtering by domain, owner, status, definition keyword, and more.
|
|
893
|
+
Includes pagination (skip/top) and sorting (orderBy).
|
|
894
|
+
|
|
895
|
+
API: POST /datagovernance/catalog/objectives/query
|
|
896
|
+
API Version: 2025-09-15-preview
|
|
897
|
+
"""
|
|
898
|
+
# Build query payload from args
|
|
899
|
+
payload = {}
|
|
900
|
+
|
|
901
|
+
# IDs and domain filters
|
|
902
|
+
if args.get("--ids"):
|
|
903
|
+
payload["ids"] = args["--ids"]
|
|
904
|
+
if args.get("--domain-ids"):
|
|
905
|
+
payload["domainIds"] = args["--domain-ids"]
|
|
906
|
+
|
|
907
|
+
# Definition keyword search (objectives-specific)
|
|
908
|
+
if args.get("--definition"):
|
|
909
|
+
payload["definition"] = args["--definition"][0]
|
|
910
|
+
|
|
911
|
+
# Owner filter
|
|
912
|
+
if args.get("--owners"):
|
|
913
|
+
payload["owners"] = args["--owners"]
|
|
914
|
+
|
|
915
|
+
# Status filters
|
|
916
|
+
if args.get("--status"):
|
|
917
|
+
payload["status"] = args["--status"][0]
|
|
918
|
+
if args.get("--multi-status"):
|
|
919
|
+
payload["multiStatus"] = args["--multi-status"]
|
|
920
|
+
|
|
921
|
+
# Pagination
|
|
922
|
+
if args.get("--skip"):
|
|
923
|
+
payload["skip"] = int(args["--skip"][0])
|
|
924
|
+
if args.get("--top"):
|
|
925
|
+
payload["top"] = int(args["--top"][0])
|
|
926
|
+
|
|
927
|
+
# Sorting
|
|
928
|
+
if args.get("--order-by-field"):
|
|
929
|
+
payload["orderby"] = [{
|
|
930
|
+
"field": args["--order-by-field"][0],
|
|
931
|
+
"direction": args.get("--order-by-direction", ["asc"])[0]
|
|
932
|
+
}]
|
|
933
|
+
|
|
934
|
+
self.method = "POST"
|
|
935
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["query_objectives"]
|
|
694
936
|
self.params = {}
|
|
937
|
+
self.payload = payload
|
|
695
938
|
|
|
696
939
|
# ========================================
|
|
697
940
|
# KEY RESULTS (Part of OKRs)
|
|
@@ -702,7 +945,7 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
702
945
|
"""Get all key results for an objective."""
|
|
703
946
|
objective_id = args.get("--objective-id", [""])[0]
|
|
704
947
|
self.method = "GET"
|
|
705
|
-
self.endpoint =
|
|
948
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_key_results"].format(objectiveId=objective_id)
|
|
706
949
|
self.params = {}
|
|
707
950
|
|
|
708
951
|
@decorator
|
|
@@ -711,7 +954,7 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
711
954
|
objective_id = args.get("--objective-id", [""])[0]
|
|
712
955
|
key_result_id = args.get("--key-result-id", [""])[0]
|
|
713
956
|
self.method = "GET"
|
|
714
|
-
self.endpoint =
|
|
957
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_key_result"].format(objectiveId=objective_id, keyResultId=key_result_id)
|
|
715
958
|
self.params = {}
|
|
716
959
|
|
|
717
960
|
@decorator
|
|
@@ -719,7 +962,7 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
719
962
|
"""Create a new key result."""
|
|
720
963
|
objective_id = args.get("--objective-id", [""])[0]
|
|
721
964
|
self.method = "POST"
|
|
722
|
-
self.endpoint =
|
|
965
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_key_results"].format(objectiveId=objective_id)
|
|
723
966
|
|
|
724
967
|
domain_id = args.get("--governance-domain-id", [""])[0]
|
|
725
968
|
progress = int(args.get("--progress", ["0"])[0])
|
|
@@ -745,7 +988,7 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
745
988
|
objective_id = args.get("--objective-id", [""])[0]
|
|
746
989
|
key_result_id = args.get("--key-result-id", [""])[0]
|
|
747
990
|
self.method = "PUT"
|
|
748
|
-
self.endpoint =
|
|
991
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_key_result"].format(objectiveId=objective_id, keyResultId=key_result_id)
|
|
749
992
|
|
|
750
993
|
domain_id = args.get("--governance-domain-id", [""])[0]
|
|
751
994
|
progress = int(args.get("--progress", ["0"])[0])
|
|
@@ -772,7 +1015,7 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
772
1015
|
objective_id = args.get("--objective-id", [""])[0]
|
|
773
1016
|
key_result_id = args.get("--key-result-id", [""])[0]
|
|
774
1017
|
self.method = "DELETE"
|
|
775
|
-
self.endpoint =
|
|
1018
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_key_result"].format(objectiveId=objective_id, keyResultId=key_result_id)
|
|
776
1019
|
self.params = {}
|
|
777
1020
|
|
|
778
1021
|
# ========================================
|
|
@@ -784,7 +1027,7 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
784
1027
|
"""Get all critical data elements in a governance domain."""
|
|
785
1028
|
domain_id = args.get("--governance-domain-id", [""])[0]
|
|
786
1029
|
self.method = "GET"
|
|
787
|
-
self.endpoint = "
|
|
1030
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_cdes"]
|
|
788
1031
|
self.params = {"domainId": domain_id} if domain_id else {}
|
|
789
1032
|
|
|
790
1033
|
@decorator
|
|
@@ -792,14 +1035,14 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
792
1035
|
"""Get a critical data element by ID."""
|
|
793
1036
|
cde_id = args.get("--cde-id", [""])[0]
|
|
794
1037
|
self.method = "GET"
|
|
795
|
-
self.endpoint =
|
|
1038
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_cde"].format(cdeId=cde_id)
|
|
796
1039
|
self.params = {}
|
|
797
1040
|
|
|
798
1041
|
@decorator
|
|
799
1042
|
def create_critical_data_element(self, args):
|
|
800
1043
|
"""Create a new critical data element."""
|
|
801
1044
|
self.method = "POST"
|
|
802
|
-
self.endpoint = "
|
|
1045
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_cdes"]
|
|
803
1046
|
|
|
804
1047
|
domain_id = args.get("--governance-domain-id", [""])[0]
|
|
805
1048
|
name = args.get("--name", [""])[0]
|
|
@@ -832,7 +1075,7 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
832
1075
|
"""Update an existing critical data element."""
|
|
833
1076
|
cde_id = args.get("--cde-id", [""])[0]
|
|
834
1077
|
self.method = "PUT"
|
|
835
|
-
self.endpoint =
|
|
1078
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_cde"].format(cdeId=cde_id)
|
|
836
1079
|
|
|
837
1080
|
domain_id = args.get("--governance-domain-id", [""])[0]
|
|
838
1081
|
name = args.get("--name", [""])[0]
|
|
@@ -866,8 +1109,132 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
866
1109
|
"""Delete a critical data element."""
|
|
867
1110
|
cde_id = args.get("--cde-id", [""])[0]
|
|
868
1111
|
self.method = "DELETE"
|
|
869
|
-
self.endpoint =
|
|
1112
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_cde"].format(cdeId=cde_id)
|
|
1113
|
+
self.params = {}
|
|
1114
|
+
|
|
1115
|
+
@decorator
|
|
1116
|
+
def query_critical_data_elements(self, args):
|
|
1117
|
+
"""Query critical data elements with advanced filters.
|
|
1118
|
+
|
|
1119
|
+
Supports filtering by domain, owner, status, name keyword, and more.
|
|
1120
|
+
Includes pagination (skip/top) and sorting (orderBy).
|
|
1121
|
+
|
|
1122
|
+
API: POST /datagovernance/catalog/criticalDataElements/query
|
|
1123
|
+
API Version: 2025-09-15-preview
|
|
1124
|
+
"""
|
|
1125
|
+
# Build query payload from args
|
|
1126
|
+
payload = {}
|
|
1127
|
+
|
|
1128
|
+
# IDs and domain filters
|
|
1129
|
+
if args.get("--ids"):
|
|
1130
|
+
payload["ids"] = args["--ids"]
|
|
1131
|
+
if args.get("--domain-ids"):
|
|
1132
|
+
payload["domainIds"] = args["--domain-ids"]
|
|
1133
|
+
|
|
1134
|
+
# Name/keyword search
|
|
1135
|
+
if args.get("--name-keyword"):
|
|
1136
|
+
payload["nameKeyword"] = args["--name-keyword"][0]
|
|
1137
|
+
|
|
1138
|
+
# Owner filter
|
|
1139
|
+
if args.get("--owners"):
|
|
1140
|
+
payload["owners"] = args["--owners"]
|
|
1141
|
+
|
|
1142
|
+
# Status filters
|
|
1143
|
+
if args.get("--status"):
|
|
1144
|
+
payload["status"] = args["--status"][0]
|
|
1145
|
+
if args.get("--multi-status"):
|
|
1146
|
+
payload["multiStatus"] = args["--multi-status"]
|
|
1147
|
+
|
|
1148
|
+
# Pagination
|
|
1149
|
+
if args.get("--skip"):
|
|
1150
|
+
payload["skip"] = int(args["--skip"][0])
|
|
1151
|
+
if args.get("--top"):
|
|
1152
|
+
payload["top"] = int(args["--top"][0])
|
|
1153
|
+
|
|
1154
|
+
# Sorting
|
|
1155
|
+
if args.get("--order-by-field"):
|
|
1156
|
+
payload["orderby"] = [{
|
|
1157
|
+
"field": args["--order-by-field"][0],
|
|
1158
|
+
"direction": args.get("--order-by-direction", ["asc"])[0]
|
|
1159
|
+
}]
|
|
1160
|
+
|
|
1161
|
+
self.method = "POST"
|
|
1162
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["query_critical_data_elements"]
|
|
870
1163
|
self.params = {}
|
|
1164
|
+
self.payload = payload
|
|
1165
|
+
|
|
1166
|
+
@decorator
|
|
1167
|
+
def create_cde_relationship(self, args):
|
|
1168
|
+
"""Create a relationship for a critical data element.
|
|
1169
|
+
|
|
1170
|
+
Creates a relationship between a CDE and another entity
|
|
1171
|
+
(e.g., critical data column, term, asset).
|
|
1172
|
+
|
|
1173
|
+
API: POST /datagovernance/catalog/criticalDataElements/{cdeId}/relationships
|
|
1174
|
+
API Version: 2025-09-15-preview
|
|
1175
|
+
"""
|
|
1176
|
+
cde_id = args.get("--cde-id", [""])[0]
|
|
1177
|
+
entity_type = args.get("--entity-type", [""])[0] # e.g., "CRITICALDATACOLUMN"
|
|
1178
|
+
entity_id = args.get("--entity-id", [""])[0]
|
|
1179
|
+
asset_id = args.get("--asset-id", [""])[0] if args.get("--asset-id") else entity_id
|
|
1180
|
+
relationship_type = args.get("--relationship-type", ["Related"])[0]
|
|
1181
|
+
description = args.get("--description", [""])[0]
|
|
1182
|
+
|
|
1183
|
+
# Build request body (same structure as data product relationships)
|
|
1184
|
+
payload = {
|
|
1185
|
+
"relationship1": {
|
|
1186
|
+
"description": description,
|
|
1187
|
+
"relationshipType": relationship_type,
|
|
1188
|
+
"assetId": asset_id,
|
|
1189
|
+
"entityId": entity_id
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
self.method = "POST"
|
|
1194
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["create_cde_relationship"].format(cdeId=cde_id)
|
|
1195
|
+
self.params = {"entityType": entity_type.upper()}
|
|
1196
|
+
self.payload = payload
|
|
1197
|
+
|
|
1198
|
+
@decorator
|
|
1199
|
+
def get_cde_relationships(self, args):
|
|
1200
|
+
"""List relationships for a critical data element.
|
|
1201
|
+
|
|
1202
|
+
Lists all relationships for a CDE, optionally filtered by entity type.
|
|
1203
|
+
|
|
1204
|
+
API: GET /datagovernance/catalog/criticalDataElements/{cdeId}/relationships
|
|
1205
|
+
API Version: 2025-09-15-preview
|
|
1206
|
+
"""
|
|
1207
|
+
cde_id = args.get("--cde-id", [""])[0]
|
|
1208
|
+
entity_type = args.get("--entity-type", [""])[0] if args.get("--entity-type") else None
|
|
1209
|
+
|
|
1210
|
+
self.method = "GET"
|
|
1211
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_cde_relationships"].format(cdeId=cde_id)
|
|
1212
|
+
|
|
1213
|
+
# Entity type is optional filter
|
|
1214
|
+
if entity_type:
|
|
1215
|
+
self.params = {"entityType": entity_type.upper()}
|
|
1216
|
+
else:
|
|
1217
|
+
self.params = {}
|
|
1218
|
+
|
|
1219
|
+
@decorator
|
|
1220
|
+
def delete_cde_relationship(self, args):
|
|
1221
|
+
"""Delete a relationship between a CDE and an entity.
|
|
1222
|
+
|
|
1223
|
+
Deletes a specific relationship identified by entity type and entity ID.
|
|
1224
|
+
|
|
1225
|
+
API: DELETE /datagovernance/catalog/criticalDataElements/{cdeId}/relationships
|
|
1226
|
+
API Version: 2025-09-15-preview
|
|
1227
|
+
"""
|
|
1228
|
+
cde_id = args.get("--cde-id", [""])[0]
|
|
1229
|
+
entity_type = args.get("--entity-type", [""])[0]
|
|
1230
|
+
entity_id = args.get("--entity-id", [""])[0]
|
|
1231
|
+
|
|
1232
|
+
self.method = "DELETE"
|
|
1233
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["delete_cde_relationship"].format(cdeId=cde_id)
|
|
1234
|
+
self.params = {
|
|
1235
|
+
"entityType": entity_type.upper(),
|
|
1236
|
+
"entityId": entity_id
|
|
1237
|
+
}
|
|
871
1238
|
|
|
872
1239
|
# ========================================
|
|
873
1240
|
# RELATIONSHIPS
|
|
@@ -969,6 +1336,252 @@ class UnifiedCatalogClient(Endpoint):
|
|
|
969
1336
|
"relationshipType": relationship_type,
|
|
970
1337
|
}
|
|
971
1338
|
|
|
1339
|
+
# ========================================
|
|
1340
|
+
# DATA POLICIES (NEW)
|
|
1341
|
+
# ========================================
|
|
1342
|
+
|
|
1343
|
+
@decorator
|
|
1344
|
+
@decorator
|
|
1345
|
+
def list_policies(self, args):
|
|
1346
|
+
"""List all data policies."""
|
|
1347
|
+
self.method = "GET"
|
|
1348
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_policies"]
|
|
1349
|
+
self.params = {}
|
|
1350
|
+
|
|
1351
|
+
@decorator
|
|
1352
|
+
def get_policy(self, args):
|
|
1353
|
+
"""Get a specific data policy by ID."""
|
|
1354
|
+
policy_id = args.get("--policy-id", [""])[0]
|
|
1355
|
+
self.method = "GET"
|
|
1356
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_policy"].format(policyId=policy_id)
|
|
1357
|
+
self.params = {}
|
|
1358
|
+
|
|
1359
|
+
@decorator
|
|
1360
|
+
def create_policy(self, args):
|
|
1361
|
+
"""Create a new data policy."""
|
|
1362
|
+
self.method = "POST"
|
|
1363
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_policies"]
|
|
1364
|
+
|
|
1365
|
+
name = args.get("--name", [""])[0]
|
|
1366
|
+
description = args.get("--description", [""])[0]
|
|
1367
|
+
policy_type = args.get("--type", ["Access"])[0]
|
|
1368
|
+
status = args.get("--status", ["Draft"])[0]
|
|
1369
|
+
|
|
1370
|
+
payload = {
|
|
1371
|
+
"name": name,
|
|
1372
|
+
"description": description,
|
|
1373
|
+
"policyType": policy_type,
|
|
1374
|
+
"status": status,
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
self.payload = payload
|
|
1378
|
+
|
|
1379
|
+
@decorator
|
|
1380
|
+
def update_policy(self, args):
|
|
1381
|
+
"""Update an existing data policy."""
|
|
1382
|
+
policy_id = args.get("--policy-id", [""])[0]
|
|
1383
|
+
self.method = "PUT"
|
|
1384
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_policy"].format(policyId=policy_id)
|
|
1385
|
+
|
|
1386
|
+
name = args.get("--name", [""])[0]
|
|
1387
|
+
description = args.get("--description", [""])[0]
|
|
1388
|
+
policy_type = args.get("--type", ["Access"])[0]
|
|
1389
|
+
status = args.get("--status", ["Draft"])[0]
|
|
1390
|
+
|
|
1391
|
+
payload = {
|
|
1392
|
+
"name": name,
|
|
1393
|
+
"description": description,
|
|
1394
|
+
"policyType": policy_type,
|
|
1395
|
+
"status": status,
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
self.payload = payload
|
|
1399
|
+
|
|
1400
|
+
@decorator
|
|
1401
|
+
def delete_policy(self, args):
|
|
1402
|
+
"""Delete a data policy."""
|
|
1403
|
+
policy_id = args.get("--policy-id", [""])[0]
|
|
1404
|
+
self.method = "DELETE"
|
|
1405
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_policy"].format(policyId=policy_id)
|
|
1406
|
+
self.params = {}
|
|
1407
|
+
|
|
1408
|
+
# ========================================
|
|
1409
|
+
# CUSTOM METADATA (NEW)
|
|
1410
|
+
# ========================================
|
|
1411
|
+
|
|
1412
|
+
@decorator
|
|
1413
|
+
def list_custom_metadata(self, args):
|
|
1414
|
+
"""List all custom metadata definitions with UC term template filter.
|
|
1415
|
+
|
|
1416
|
+
Uses Atlas API with includeTermTemplate=true to get UC Custom Metadata.
|
|
1417
|
+
This is the same API used by Purview UI for UC metadata.
|
|
1418
|
+
"""
|
|
1419
|
+
self.method = "GET"
|
|
1420
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_custom_metadata"]
|
|
1421
|
+
self.params = {
|
|
1422
|
+
"type": "business_metadata",
|
|
1423
|
+
"includeTermTemplate": "true",
|
|
1424
|
+
"api-version": "2022-11-03"
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
@decorator
|
|
1428
|
+
def get_custom_metadata(self, args):
|
|
1429
|
+
"""Get custom metadata (business metadata) for a specific asset.
|
|
1430
|
+
|
|
1431
|
+
Uses Entity API to get business metadata attached to a GUID.
|
|
1432
|
+
This returns all business metadata groups attached to the entity.
|
|
1433
|
+
"""
|
|
1434
|
+
asset_id = args.get("--asset-id", [""])[0]
|
|
1435
|
+
self.method = "GET"
|
|
1436
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_custom_metadata"].format(guid=asset_id)
|
|
1437
|
+
self.params = {
|
|
1438
|
+
"api-version": "2023-09-01",
|
|
1439
|
+
"minExtInfo": "false",
|
|
1440
|
+
"ignoreRelationships": "true"
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
@decorator
|
|
1444
|
+
def add_custom_metadata(self, args):
|
|
1445
|
+
"""Add custom metadata (business metadata) to an asset.
|
|
1446
|
+
|
|
1447
|
+
Uses Entity API to add business metadata to a GUID.
|
|
1448
|
+
Format: { "GroupName": { "attribute1": "value1", "attribute2": "value2" } }
|
|
1449
|
+
"""
|
|
1450
|
+
asset_id = args.get("--asset-id", [""])[0]
|
|
1451
|
+
self.method = "POST"
|
|
1452
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["add_custom_metadata"].format(guid=asset_id)
|
|
1453
|
+
self.params = {"api-version": "2023-09-01"}
|
|
1454
|
+
|
|
1455
|
+
# Build payload based on parameters
|
|
1456
|
+
key = args.get("--key", [""])[0]
|
|
1457
|
+
value = args.get("--value", [""])[0]
|
|
1458
|
+
group = args.get("--group", ["Custom"])[0] # Default group name
|
|
1459
|
+
|
|
1460
|
+
# Format: { "GroupName": { "attributeName": "value" } }
|
|
1461
|
+
payload = {
|
|
1462
|
+
group: {
|
|
1463
|
+
key: value
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
self.payload = payload
|
|
1468
|
+
|
|
1469
|
+
@decorator
|
|
1470
|
+
def update_custom_metadata(self, args):
|
|
1471
|
+
"""Update custom metadata (business metadata) for an asset.
|
|
1472
|
+
|
|
1473
|
+
Uses Entity API to update business metadata on a GUID.
|
|
1474
|
+
POST method overwrites existing values for the specified attributes.
|
|
1475
|
+
Format: { "GroupName": { "attribute1": "newValue" } }
|
|
1476
|
+
"""
|
|
1477
|
+
asset_id = args.get("--asset-id", [""])[0]
|
|
1478
|
+
self.method = "POST"
|
|
1479
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["update_custom_metadata"].format(guid=asset_id)
|
|
1480
|
+
self.params = {"api-version": "2023-09-01"}
|
|
1481
|
+
|
|
1482
|
+
key = args.get("--key", [""])[0]
|
|
1483
|
+
value = args.get("--value", [""])[0]
|
|
1484
|
+
group = args.get("--group", ["Custom"])[0]
|
|
1485
|
+
|
|
1486
|
+
payload = {
|
|
1487
|
+
group: {
|
|
1488
|
+
key: value
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
self.payload = payload
|
|
1493
|
+
|
|
1494
|
+
@decorator
|
|
1495
|
+
def delete_custom_metadata(self, args):
|
|
1496
|
+
"""Delete custom metadata (business metadata) from an asset.
|
|
1497
|
+
|
|
1498
|
+
Uses Entity API to remove business metadata from a GUID.
|
|
1499
|
+
Removes entire business metadata group by passing it in params + empty payload.
|
|
1500
|
+
"""
|
|
1501
|
+
asset_id = args.get("--asset-id", [""])[0]
|
|
1502
|
+
group = args.get("--group", [""])[0]
|
|
1503
|
+
|
|
1504
|
+
if not group:
|
|
1505
|
+
raise ValueError("--group parameter is required to delete business metadata")
|
|
1506
|
+
|
|
1507
|
+
self.method = "DELETE"
|
|
1508
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["delete_custom_metadata"].format(guid=asset_id)
|
|
1509
|
+
self.params = {
|
|
1510
|
+
"api-version": "2023-09-01"
|
|
1511
|
+
}
|
|
1512
|
+
# Payload must contain the group with empty dict to delete entire group
|
|
1513
|
+
self.payload = {
|
|
1514
|
+
group: {}
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
# ========================================
|
|
1518
|
+
# CUSTOM ATTRIBUTES (NEW)
|
|
1519
|
+
# ========================================
|
|
1520
|
+
|
|
1521
|
+
@decorator
|
|
1522
|
+
def list_custom_attributes(self, args):
|
|
1523
|
+
"""List all custom attribute definitions."""
|
|
1524
|
+
self.method = "GET"
|
|
1525
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_custom_attributes"]
|
|
1526
|
+
self.params = {}
|
|
1527
|
+
|
|
1528
|
+
@decorator
|
|
1529
|
+
def get_custom_attribute(self, args):
|
|
1530
|
+
"""Get a specific custom attribute definition."""
|
|
1531
|
+
attribute_id = args.get("--attribute-id", [""])[0]
|
|
1532
|
+
self.method = "GET"
|
|
1533
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_custom_attribute"].format(attributeId=attribute_id)
|
|
1534
|
+
self.params = {}
|
|
1535
|
+
|
|
1536
|
+
@decorator
|
|
1537
|
+
def create_custom_attribute(self, args):
|
|
1538
|
+
"""Create a new custom attribute definition."""
|
|
1539
|
+
self.method = "POST"
|
|
1540
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["list_custom_attributes"]
|
|
1541
|
+
|
|
1542
|
+
name = args.get("--name", [""])[0]
|
|
1543
|
+
description = args.get("--description", [""])[0]
|
|
1544
|
+
data_type = args.get("--type", ["string"])[0]
|
|
1545
|
+
required = args.get("--required", ["false"])[0].lower() == "true"
|
|
1546
|
+
|
|
1547
|
+
payload = {
|
|
1548
|
+
"name": name,
|
|
1549
|
+
"description": description,
|
|
1550
|
+
"dataType": data_type,
|
|
1551
|
+
"required": required,
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
self.payload = payload
|
|
1555
|
+
|
|
1556
|
+
@decorator
|
|
1557
|
+
def update_custom_attribute(self, args):
|
|
1558
|
+
"""Update a custom attribute definition."""
|
|
1559
|
+
attribute_id = args.get("--attribute-id", [""])[0]
|
|
1560
|
+
self.method = "PUT"
|
|
1561
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_custom_attribute"].format(attributeId=attribute_id)
|
|
1562
|
+
|
|
1563
|
+
name = args.get("--name", [""])[0]
|
|
1564
|
+
description = args.get("--description", [""])[0]
|
|
1565
|
+
data_type = args.get("--type", ["string"])[0]
|
|
1566
|
+
required = args.get("--required", ["false"])[0].lower() == "true"
|
|
1567
|
+
|
|
1568
|
+
payload = {
|
|
1569
|
+
"name": name,
|
|
1570
|
+
"description": description,
|
|
1571
|
+
"dataType": data_type,
|
|
1572
|
+
"required": required,
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
self.payload = payload
|
|
1576
|
+
|
|
1577
|
+
@decorator
|
|
1578
|
+
def delete_custom_attribute(self, args):
|
|
1579
|
+
"""Delete a custom attribute definition."""
|
|
1580
|
+
attribute_id = args.get("--attribute-id", [""])[0]
|
|
1581
|
+
self.method = "DELETE"
|
|
1582
|
+
self.endpoint = ENDPOINTS["unified_catalog"]["get_custom_attribute"].format(attributeId=attribute_id)
|
|
1583
|
+
self.params = {}
|
|
1584
|
+
|
|
972
1585
|
# ========================================
|
|
973
1586
|
# UTILITY METHODS
|
|
974
1587
|
# ========================================
|
|
@@ -986,6 +1599,9 @@ Available Operations:
|
|
|
986
1599
|
- Objectives (OKRs): list, get, create, update, delete
|
|
987
1600
|
- Key Results: list, get, create, update, delete
|
|
988
1601
|
- Critical Data Elements: list, get, create, update, delete
|
|
1602
|
+
- Data Policies: list, get, create, update, delete (NEW)
|
|
1603
|
+
- Custom Metadata: list, get, add, update, delete (NEW)
|
|
1604
|
+
- Custom Attributes: list, get, create, update, delete (NEW)
|
|
989
1605
|
- Relationships: create, delete (between terms, data products, CDEs)
|
|
990
1606
|
|
|
991
1607
|
Use --payloadFile to provide JSON payload for create/update operations.
|