pvw-cli 1.0.8__py3-none-any.whl → 1.0.9__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/search.py +201 -10
- purviewcli/cli/unified_catalog.py +188 -97
- purviewcli/client/_unified_catalog.py +68 -22
- purviewcli/client/sync_client.py +6 -6
- {pvw_cli-1.0.8.dist-info → pvw_cli-1.0.9.dist-info}/METADATA +360 -18
- {pvw_cli-1.0.8.dist-info → pvw_cli-1.0.9.dist-info}/RECORD +10 -10
- {pvw_cli-1.0.8.dist-info → pvw_cli-1.0.9.dist-info}/WHEEL +0 -0
- {pvw_cli-1.0.8.dist-info → pvw_cli-1.0.9.dist-info}/entry_points.txt +0 -0
- {pvw_cli-1.0.8.dist-info → pvw_cli-1.0.9.dist-info}/top_level.txt +0 -0
|
@@ -11,11 +11,20 @@ import os
|
|
|
11
11
|
from rich.console import Console
|
|
12
12
|
from rich.table import Table
|
|
13
13
|
from rich.text import Text
|
|
14
|
+
from rich.syntax import Syntax
|
|
14
15
|
from purviewcli.client._unified_catalog import UnifiedCatalogClient
|
|
15
16
|
|
|
16
17
|
console = Console()
|
|
17
18
|
|
|
18
19
|
|
|
20
|
+
def _format_json_output(data):
|
|
21
|
+
"""Format JSON output with syntax highlighting using Rich"""
|
|
22
|
+
# Pretty print JSON with syntax highlighting
|
|
23
|
+
json_str = json.dumps(data, indent=2)
|
|
24
|
+
syntax = Syntax(json_str, "json", theme="monokai", line_numbers=True)
|
|
25
|
+
console.print(syntax)
|
|
26
|
+
|
|
27
|
+
|
|
19
28
|
@click.group()
|
|
20
29
|
def uc():
|
|
21
30
|
"""Manage Unified Catalog in Microsoft Purview (domains, terms, data products, OKRs, CDEs)."""
|
|
@@ -88,7 +97,8 @@ def create(name, description, type, owner_id, status):
|
|
|
88
97
|
|
|
89
98
|
|
|
90
99
|
@domain.command(name="list")
|
|
91
|
-
|
|
100
|
+
@click.option("--json", "output_json", is_flag=True, help="Output results in JSON format")
|
|
101
|
+
def list_domains(output_json):
|
|
92
102
|
"""List all governance domains."""
|
|
93
103
|
try:
|
|
94
104
|
client = UnifiedCatalogClient()
|
|
@@ -111,6 +121,11 @@ def list_domains():
|
|
|
111
121
|
console.print("[yellow]No governance domains found.[/yellow]")
|
|
112
122
|
return
|
|
113
123
|
|
|
124
|
+
# Output in JSON format if requested
|
|
125
|
+
if output_json:
|
|
126
|
+
_format_json_output(domains)
|
|
127
|
+
return
|
|
128
|
+
|
|
114
129
|
table = Table(title="Governance Domains")
|
|
115
130
|
table.add_column("ID", style="cyan")
|
|
116
131
|
table.add_column("Name", style="green")
|
|
@@ -243,7 +258,8 @@ def create(
|
|
|
243
258
|
@dataproduct.command(name="list")
|
|
244
259
|
@click.option("--domain-id", required=False, help="Governance domain ID (optional filter)")
|
|
245
260
|
@click.option("--status", required=False, help="Status filter (Draft, Published, Archived)")
|
|
246
|
-
|
|
261
|
+
@click.option("--json", "output_json", is_flag=True, help="Output results in JSON format")
|
|
262
|
+
def list_data_products(domain_id, status, output_json):
|
|
247
263
|
"""List all data products (optionally filtered by domain or status)."""
|
|
248
264
|
try:
|
|
249
265
|
client = UnifiedCatalogClient()
|
|
@@ -274,6 +290,11 @@ def list_data_products(domain_id, status):
|
|
|
274
290
|
console.print(f"[yellow]No data products found{filter_msg}.[/yellow]")
|
|
275
291
|
return
|
|
276
292
|
|
|
293
|
+
# Output in JSON format if requested
|
|
294
|
+
if output_json:
|
|
295
|
+
_format_json_output(products)
|
|
296
|
+
return
|
|
297
|
+
|
|
277
298
|
table = Table(title="Data Products")
|
|
278
299
|
table.add_column("ID", style="cyan")
|
|
279
300
|
table.add_column("Name", style="green")
|
|
@@ -326,6 +347,7 @@ def show(product_id):
|
|
|
326
347
|
# GLOSSARY TERMS
|
|
327
348
|
# ========================================
|
|
328
349
|
|
|
350
|
+
|
|
329
351
|
@uc.group()
|
|
330
352
|
def term():
|
|
331
353
|
"""Manage glossary terms."""
|
|
@@ -336,26 +358,40 @@ def term():
|
|
|
336
358
|
@click.option("--name", required=True, help="Name of the glossary term")
|
|
337
359
|
@click.option("--description", required=False, default="", help="Rich text description of the term")
|
|
338
360
|
@click.option("--domain-id", required=True, help="Governance domain ID")
|
|
339
|
-
@click.option(
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
361
|
+
@click.option(
|
|
362
|
+
"--status",
|
|
363
|
+
required=False,
|
|
364
|
+
default="Draft",
|
|
365
|
+
type=click.Choice(["Draft", "Published", "Archived"]),
|
|
366
|
+
help="Status of the term",
|
|
367
|
+
)
|
|
368
|
+
@click.option(
|
|
369
|
+
"--acronym",
|
|
370
|
+
required=False,
|
|
371
|
+
help="Acronyms for the term (can be specified multiple times)",
|
|
372
|
+
multiple=True,
|
|
373
|
+
)
|
|
374
|
+
@click.option(
|
|
375
|
+
"--owner-id",
|
|
376
|
+
required=False,
|
|
377
|
+
help="Owner Entra ID (can be specified multiple times)",
|
|
378
|
+
multiple=True,
|
|
379
|
+
)
|
|
344
380
|
@click.option("--resource-name", required=False, help="Resource name for additional reading")
|
|
345
381
|
@click.option("--resource-url", required=False, help="Resource URL for additional reading")
|
|
346
382
|
def create(name, description, domain_id, status, acronym, owner_id, resource_name, resource_url):
|
|
347
383
|
"""Create a new glossary term."""
|
|
348
384
|
try:
|
|
349
385
|
client = UnifiedCatalogClient()
|
|
350
|
-
|
|
386
|
+
|
|
351
387
|
# Build args dictionary
|
|
352
388
|
args = {
|
|
353
389
|
"--name": [name],
|
|
354
390
|
"--description": [description],
|
|
355
391
|
"--governance-domain-id": [domain_id],
|
|
356
|
-
"--status": [status]
|
|
392
|
+
"--status": [status],
|
|
357
393
|
}
|
|
358
|
-
|
|
394
|
+
|
|
359
395
|
if acronym:
|
|
360
396
|
args["--acronyms"] = list(acronym)
|
|
361
397
|
if owner_id:
|
|
@@ -363,71 +399,86 @@ def create(name, description, domain_id, status, acronym, owner_id, resource_nam
|
|
|
363
399
|
if resource_name and resource_url:
|
|
364
400
|
args["--resource-name"] = [resource_name]
|
|
365
401
|
args["--resource-url"] = [resource_url]
|
|
366
|
-
|
|
402
|
+
|
|
367
403
|
result = client.create_term(args)
|
|
368
|
-
|
|
404
|
+
|
|
369
405
|
if not result:
|
|
370
406
|
console.print("[red]ERROR:[/red] No response received")
|
|
371
407
|
return
|
|
372
408
|
if isinstance(result, dict) and "error" in result:
|
|
373
409
|
console.print(f"[red]ERROR:[/red] {result.get('error', 'Unknown error')}")
|
|
374
410
|
return
|
|
375
|
-
|
|
411
|
+
|
|
376
412
|
console.print(f"[green]✅ SUCCESS:[/green] Created glossary term '{name}'")
|
|
377
413
|
console.print(json.dumps(result, indent=2))
|
|
378
|
-
|
|
414
|
+
|
|
379
415
|
except Exception as e:
|
|
380
416
|
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
381
417
|
|
|
382
418
|
|
|
383
419
|
@term.command(name="list")
|
|
384
420
|
@click.option("--domain-id", required=True, help="Governance domain ID to list terms from")
|
|
385
|
-
|
|
421
|
+
@click.option("--json", "output_json", is_flag=True, help="Output results in JSON format")
|
|
422
|
+
def list_terms(domain_id, output_json):
|
|
386
423
|
"""List all glossary terms in a governance domain."""
|
|
387
424
|
try:
|
|
388
425
|
client = UnifiedCatalogClient()
|
|
389
426
|
args = {"--governance-domain-id": [domain_id]}
|
|
390
427
|
result = client.get_terms(args)
|
|
391
|
-
|
|
428
|
+
|
|
392
429
|
if not result:
|
|
393
430
|
console.print("[yellow]No glossary terms found.[/yellow]")
|
|
394
431
|
return
|
|
395
|
-
|
|
396
|
-
#
|
|
432
|
+
|
|
433
|
+
# The API returns glossaries with terms nested inside
|
|
434
|
+
# Extract all terms from all glossaries
|
|
435
|
+
all_terms = []
|
|
436
|
+
|
|
397
437
|
if isinstance(result, (list, tuple)):
|
|
398
|
-
|
|
438
|
+
glossaries = result
|
|
399
439
|
elif isinstance(result, dict):
|
|
400
|
-
|
|
440
|
+
glossaries = result.get("value", [])
|
|
401
441
|
else:
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
442
|
+
glossaries = []
|
|
443
|
+
|
|
444
|
+
# Extract terms from glossaries
|
|
445
|
+
for glossary in glossaries:
|
|
446
|
+
if isinstance(glossary, dict) and "terms" in glossary:
|
|
447
|
+
for term in glossary["terms"]:
|
|
448
|
+
all_terms.append(
|
|
449
|
+
{
|
|
450
|
+
"id": term.get("termGuid"),
|
|
451
|
+
"name": term.get("displayText"),
|
|
452
|
+
"glossary": glossary.get("name"),
|
|
453
|
+
"glossary_id": glossary.get("guid"),
|
|
454
|
+
}
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
if not all_terms:
|
|
405
458
|
console.print("[yellow]No glossary terms found.[/yellow]")
|
|
406
459
|
return
|
|
407
|
-
|
|
460
|
+
|
|
461
|
+
# Output in JSON format if requested
|
|
462
|
+
if output_json:
|
|
463
|
+
_format_json_output(all_terms)
|
|
464
|
+
return
|
|
465
|
+
|
|
408
466
|
table = Table(title="Glossary Terms")
|
|
409
|
-
table.add_column("ID", style="cyan")
|
|
467
|
+
table.add_column("Term ID", style="cyan")
|
|
410
468
|
table.add_column("Name", style="green")
|
|
411
|
-
table.add_column("
|
|
412
|
-
table.add_column("
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
for term in terms:
|
|
416
|
-
acronyms = ", ".join(term.get("acronyms", []))
|
|
417
|
-
desc = term.get("description", "")
|
|
418
|
-
if len(desc) > 50:
|
|
419
|
-
desc = desc[:50] + "..."
|
|
420
|
-
|
|
469
|
+
table.add_column("Glossary", style="yellow")
|
|
470
|
+
table.add_column("Glossary ID", style="blue")
|
|
471
|
+
|
|
472
|
+
for term in all_terms:
|
|
421
473
|
table.add_row(
|
|
422
474
|
term.get("id", "N/A"),
|
|
423
475
|
term.get("name", "N/A"),
|
|
424
|
-
term.get("
|
|
425
|
-
|
|
426
|
-
desc
|
|
476
|
+
term.get("glossary", "N/A"),
|
|
477
|
+
term.get("glossary_id", "N/A"),
|
|
427
478
|
)
|
|
428
|
-
|
|
479
|
+
|
|
429
480
|
console.print(table)
|
|
430
|
-
|
|
481
|
+
|
|
431
482
|
except Exception as e:
|
|
432
483
|
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
433
484
|
|
|
@@ -440,16 +491,16 @@ def show(term_id):
|
|
|
440
491
|
client = UnifiedCatalogClient()
|
|
441
492
|
args = {"--term-id": [term_id]}
|
|
442
493
|
result = client.get_term_by_id(args)
|
|
443
|
-
|
|
494
|
+
|
|
444
495
|
if not result:
|
|
445
496
|
console.print("[red]ERROR:[/red] No response received")
|
|
446
497
|
return
|
|
447
498
|
if isinstance(result, dict) and "error" in result:
|
|
448
499
|
console.print(f"[red]ERROR:[/red] {result.get('error', 'Term not found')}")
|
|
449
500
|
return
|
|
450
|
-
|
|
501
|
+
|
|
451
502
|
console.print(json.dumps(result, indent=2))
|
|
452
|
-
|
|
503
|
+
|
|
453
504
|
except Exception as e:
|
|
454
505
|
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
455
506
|
|
|
@@ -458,6 +509,7 @@ def show(term_id):
|
|
|
458
509
|
# OBJECTIVES AND KEY RESULTS (OKRs)
|
|
459
510
|
# ========================================
|
|
460
511
|
|
|
512
|
+
|
|
461
513
|
@uc.group()
|
|
462
514
|
def objective():
|
|
463
515
|
"""Manage objectives and key results (OKRs)."""
|
|
@@ -467,56 +519,68 @@ def objective():
|
|
|
467
519
|
@objective.command()
|
|
468
520
|
@click.option("--definition", required=True, help="Definition of the objective")
|
|
469
521
|
@click.option("--domain-id", required=True, help="Governance domain ID")
|
|
470
|
-
@click.option(
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
522
|
+
@click.option(
|
|
523
|
+
"--status",
|
|
524
|
+
required=False,
|
|
525
|
+
default="Draft",
|
|
526
|
+
type=click.Choice(["Draft", "Published", "Archived"]),
|
|
527
|
+
help="Status of the objective",
|
|
528
|
+
)
|
|
529
|
+
@click.option(
|
|
530
|
+
"--owner-id",
|
|
531
|
+
required=False,
|
|
532
|
+
help="Owner Entra ID (can be specified multiple times)",
|
|
533
|
+
multiple=True,
|
|
534
|
+
)
|
|
535
|
+
@click.option(
|
|
536
|
+
"--target-date", required=False, help="Target date (ISO format: 2025-12-30T14:00:00.000Z)"
|
|
537
|
+
)
|
|
475
538
|
def create(definition, domain_id, status, owner_id, target_date):
|
|
476
539
|
"""Create a new objective."""
|
|
477
540
|
try:
|
|
478
541
|
client = UnifiedCatalogClient()
|
|
479
|
-
|
|
542
|
+
|
|
480
543
|
args = {
|
|
481
544
|
"--definition": [definition],
|
|
482
545
|
"--governance-domain-id": [domain_id],
|
|
483
|
-
"--status": [status]
|
|
546
|
+
"--status": [status],
|
|
484
547
|
}
|
|
485
|
-
|
|
548
|
+
|
|
486
549
|
if owner_id:
|
|
487
550
|
args["--owner-id"] = list(owner_id)
|
|
488
551
|
if target_date:
|
|
489
552
|
args["--target-date"] = [target_date]
|
|
490
|
-
|
|
553
|
+
|
|
491
554
|
result = client.create_objective(args)
|
|
492
|
-
|
|
555
|
+
|
|
493
556
|
if not result:
|
|
494
557
|
console.print("[red]ERROR:[/red] No response received")
|
|
495
558
|
return
|
|
496
559
|
if isinstance(result, dict) and "error" in result:
|
|
497
560
|
console.print(f"[red]ERROR:[/red] {result.get('error', 'Unknown error')}")
|
|
498
561
|
return
|
|
499
|
-
|
|
562
|
+
|
|
500
563
|
console.print(f"[green]✅ SUCCESS:[/green] Created objective")
|
|
501
564
|
console.print(json.dumps(result, indent=2))
|
|
502
|
-
|
|
565
|
+
|
|
503
566
|
except Exception as e:
|
|
504
567
|
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
505
568
|
|
|
506
569
|
|
|
507
570
|
@objective.command(name="list")
|
|
508
571
|
@click.option("--domain-id", required=True, help="Governance domain ID to list objectives from")
|
|
509
|
-
|
|
572
|
+
@click.option("--json", "output_json", is_flag=True, help="Output results in JSON format")
|
|
573
|
+
def list_objectives(domain_id, output_json):
|
|
510
574
|
"""List all objectives in a governance domain."""
|
|
511
575
|
try:
|
|
512
576
|
client = UnifiedCatalogClient()
|
|
513
577
|
args = {"--governance-domain-id": [domain_id]}
|
|
514
578
|
result = client.get_objectives(args)
|
|
515
|
-
|
|
579
|
+
|
|
516
580
|
if not result:
|
|
517
581
|
console.print("[yellow]No objectives found.[/yellow]")
|
|
518
582
|
return
|
|
519
|
-
|
|
583
|
+
|
|
520
584
|
# Handle response format
|
|
521
585
|
if isinstance(result, (list, tuple)):
|
|
522
586
|
objectives = result
|
|
@@ -524,31 +588,36 @@ def list_objectives(domain_id):
|
|
|
524
588
|
objectives = result.get("value", [])
|
|
525
589
|
else:
|
|
526
590
|
objectives = []
|
|
527
|
-
|
|
591
|
+
|
|
528
592
|
if not objectives:
|
|
529
593
|
console.print("[yellow]No objectives found.[/yellow]")
|
|
530
594
|
return
|
|
531
|
-
|
|
595
|
+
|
|
596
|
+
# Output in JSON format if requested
|
|
597
|
+
if output_json:
|
|
598
|
+
_format_json_output(objectives)
|
|
599
|
+
return
|
|
600
|
+
|
|
532
601
|
table = Table(title="Objectives")
|
|
533
602
|
table.add_column("ID", style="cyan")
|
|
534
603
|
table.add_column("Definition", style="green")
|
|
535
604
|
table.add_column("Status", style="yellow")
|
|
536
605
|
table.add_column("Target Date", style="blue")
|
|
537
|
-
|
|
606
|
+
|
|
538
607
|
for obj in objectives:
|
|
539
608
|
definition = obj.get("definition", "")
|
|
540
609
|
if len(definition) > 50:
|
|
541
610
|
definition = definition[:50] + "..."
|
|
542
|
-
|
|
611
|
+
|
|
543
612
|
table.add_row(
|
|
544
613
|
obj.get("id", "N/A"),
|
|
545
614
|
definition,
|
|
546
615
|
obj.get("status", "N/A"),
|
|
547
|
-
obj.get("targetDate", "N/A")
|
|
616
|
+
obj.get("targetDate", "N/A"),
|
|
548
617
|
)
|
|
549
|
-
|
|
618
|
+
|
|
550
619
|
console.print(table)
|
|
551
|
-
|
|
620
|
+
|
|
552
621
|
except Exception as e:
|
|
553
622
|
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
554
623
|
|
|
@@ -561,16 +630,16 @@ def show(objective_id):
|
|
|
561
630
|
client = UnifiedCatalogClient()
|
|
562
631
|
args = {"--objective-id": [objective_id]}
|
|
563
632
|
result = client.get_objective_by_id(args)
|
|
564
|
-
|
|
633
|
+
|
|
565
634
|
if not result:
|
|
566
635
|
console.print("[red]ERROR:[/red] No response received")
|
|
567
636
|
return
|
|
568
637
|
if isinstance(result, dict) and "error" in result:
|
|
569
638
|
console.print(f"[red]ERROR:[/red] {result.get('error', 'Objective not found')}")
|
|
570
639
|
return
|
|
571
|
-
|
|
640
|
+
|
|
572
641
|
console.print(json.dumps(result, indent=2))
|
|
573
|
-
|
|
642
|
+
|
|
574
643
|
except Exception as e:
|
|
575
644
|
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
576
645
|
|
|
@@ -579,6 +648,7 @@ def show(objective_id):
|
|
|
579
648
|
# CRITICAL DATA ELEMENTS (CDEs)
|
|
580
649
|
# ========================================
|
|
581
650
|
|
|
651
|
+
|
|
582
652
|
@uc.group()
|
|
583
653
|
def cde():
|
|
584
654
|
"""Manage critical data elements."""
|
|
@@ -589,58 +659,71 @@ def cde():
|
|
|
589
659
|
@click.option("--name", required=True, help="Name of the critical data element")
|
|
590
660
|
@click.option("--description", required=False, default="", help="Description of the CDE")
|
|
591
661
|
@click.option("--domain-id", required=True, help="Governance domain ID")
|
|
592
|
-
@click.option(
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
@click.option(
|
|
662
|
+
@click.option(
|
|
663
|
+
"--data-type",
|
|
664
|
+
required=True,
|
|
665
|
+
type=click.Choice(["String", "Number", "Boolean", "Date", "DateTime"]),
|
|
666
|
+
help="Data type of the CDE",
|
|
667
|
+
)
|
|
668
|
+
@click.option(
|
|
669
|
+
"--status",
|
|
670
|
+
required=False,
|
|
671
|
+
default="Draft",
|
|
672
|
+
type=click.Choice(["Draft", "Published", "Archived"]),
|
|
673
|
+
help="Status of the CDE",
|
|
674
|
+
)
|
|
675
|
+
@click.option(
|
|
676
|
+
"--owner-id",
|
|
677
|
+
required=False,
|
|
678
|
+
help="Owner Entra ID (can be specified multiple times)",
|
|
679
|
+
multiple=True,
|
|
680
|
+
)
|
|
599
681
|
def create(name, description, domain_id, data_type, status, owner_id):
|
|
600
682
|
"""Create a new critical data element."""
|
|
601
683
|
try:
|
|
602
684
|
client = UnifiedCatalogClient()
|
|
603
|
-
|
|
685
|
+
|
|
604
686
|
args = {
|
|
605
687
|
"--name": [name],
|
|
606
688
|
"--description": [description],
|
|
607
689
|
"--governance-domain-id": [domain_id],
|
|
608
690
|
"--data-type": [data_type],
|
|
609
|
-
"--status": [status]
|
|
691
|
+
"--status": [status],
|
|
610
692
|
}
|
|
611
|
-
|
|
693
|
+
|
|
612
694
|
if owner_id:
|
|
613
695
|
args["--owner-id"] = list(owner_id)
|
|
614
|
-
|
|
696
|
+
|
|
615
697
|
result = client.create_critical_data_element(args)
|
|
616
|
-
|
|
698
|
+
|
|
617
699
|
if not result:
|
|
618
700
|
console.print("[red]ERROR:[/red] No response received")
|
|
619
701
|
return
|
|
620
702
|
if isinstance(result, dict) and "error" in result:
|
|
621
703
|
console.print(f"[red]ERROR:[/red] {result.get('error', 'Unknown error')}")
|
|
622
704
|
return
|
|
623
|
-
|
|
705
|
+
|
|
624
706
|
console.print(f"[green]✅ SUCCESS:[/green] Created critical data element '{name}'")
|
|
625
707
|
console.print(json.dumps(result, indent=2))
|
|
626
|
-
|
|
708
|
+
|
|
627
709
|
except Exception as e:
|
|
628
710
|
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
629
711
|
|
|
630
712
|
|
|
631
713
|
@cde.command(name="list")
|
|
632
714
|
@click.option("--domain-id", required=True, help="Governance domain ID to list CDEs from")
|
|
633
|
-
|
|
715
|
+
@click.option("--json", "output_json", is_flag=True, help="Output results in JSON format")
|
|
716
|
+
def list_cdes(domain_id, output_json):
|
|
634
717
|
"""List all critical data elements in a governance domain."""
|
|
635
718
|
try:
|
|
636
719
|
client = UnifiedCatalogClient()
|
|
637
720
|
args = {"--governance-domain-id": [domain_id]}
|
|
638
721
|
result = client.get_critical_data_elements(args)
|
|
639
|
-
|
|
722
|
+
|
|
640
723
|
if not result:
|
|
641
724
|
console.print("[yellow]No critical data elements found.[/yellow]")
|
|
642
725
|
return
|
|
643
|
-
|
|
726
|
+
|
|
644
727
|
# Handle response format
|
|
645
728
|
if isinstance(result, (list, tuple)):
|
|
646
729
|
cdes = result
|
|
@@ -648,33 +731,38 @@ def list_cdes(domain_id):
|
|
|
648
731
|
cdes = result.get("value", [])
|
|
649
732
|
else:
|
|
650
733
|
cdes = []
|
|
651
|
-
|
|
734
|
+
|
|
652
735
|
if not cdes:
|
|
653
736
|
console.print("[yellow]No critical data elements found.[/yellow]")
|
|
654
737
|
return
|
|
655
|
-
|
|
738
|
+
|
|
739
|
+
# Output in JSON format if requested
|
|
740
|
+
if output_json:
|
|
741
|
+
_format_json_output(cdes)
|
|
742
|
+
return
|
|
743
|
+
|
|
656
744
|
table = Table(title="Critical Data Elements")
|
|
657
745
|
table.add_column("ID", style="cyan")
|
|
658
746
|
table.add_column("Name", style="green")
|
|
659
747
|
table.add_column("Data Type", style="blue")
|
|
660
748
|
table.add_column("Status", style="yellow")
|
|
661
749
|
table.add_column("Description", style="white")
|
|
662
|
-
|
|
750
|
+
|
|
663
751
|
for cde_item in cdes:
|
|
664
752
|
desc = cde_item.get("description", "")
|
|
665
753
|
if len(desc) > 30:
|
|
666
754
|
desc = desc[:30] + "..."
|
|
667
|
-
|
|
755
|
+
|
|
668
756
|
table.add_row(
|
|
669
757
|
cde_item.get("id", "N/A"),
|
|
670
758
|
cde_item.get("name", "N/A"),
|
|
671
759
|
cde_item.get("dataType", "N/A"),
|
|
672
760
|
cde_item.get("status", "N/A"),
|
|
673
|
-
desc
|
|
761
|
+
desc,
|
|
674
762
|
)
|
|
675
|
-
|
|
763
|
+
|
|
676
764
|
console.print(table)
|
|
677
|
-
|
|
765
|
+
|
|
678
766
|
except Exception as e:
|
|
679
767
|
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
680
768
|
|
|
@@ -687,16 +775,16 @@ def show(cde_id):
|
|
|
687
775
|
client = UnifiedCatalogClient()
|
|
688
776
|
args = {"--cde-id": [cde_id]}
|
|
689
777
|
result = client.get_critical_data_element_by_id(args)
|
|
690
|
-
|
|
778
|
+
|
|
691
779
|
if not result:
|
|
692
780
|
console.print("[red]ERROR:[/red] No response received")
|
|
693
781
|
return
|
|
694
782
|
if isinstance(result, dict) and "error" in result:
|
|
695
783
|
console.print(f"[red]ERROR:[/red] {result.get('error', 'CDE not found')}")
|
|
696
784
|
return
|
|
697
|
-
|
|
785
|
+
|
|
698
786
|
console.print(json.dumps(result, indent=2))
|
|
699
|
-
|
|
787
|
+
|
|
700
788
|
except Exception as e:
|
|
701
789
|
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
702
790
|
|
|
@@ -705,6 +793,7 @@ def show(cde_id):
|
|
|
705
793
|
# HEALTH MANAGEMENT (Preview)
|
|
706
794
|
# ========================================
|
|
707
795
|
|
|
796
|
+
|
|
708
797
|
@uc.group()
|
|
709
798
|
def health():
|
|
710
799
|
"""Manage health controls and actions (preview)."""
|
|
@@ -718,7 +807,7 @@ def list_controls():
|
|
|
718
807
|
console.print("This feature is coming soon to Microsoft Purview Unified Catalog")
|
|
719
808
|
|
|
720
809
|
|
|
721
|
-
@health.command(name="actions")
|
|
810
|
+
@health.command(name="actions")
|
|
722
811
|
def list_actions():
|
|
723
812
|
"""List health actions (preview - not yet implemented)."""
|
|
724
813
|
console.print("[yellow]🚧 Health Actions are not yet implemented in the API[/yellow]")
|
|
@@ -736,6 +825,7 @@ def data_quality():
|
|
|
736
825
|
# CUSTOM ATTRIBUTES (Coming Soon)
|
|
737
826
|
# ========================================
|
|
738
827
|
|
|
828
|
+
|
|
739
829
|
@uc.group()
|
|
740
830
|
def attribute():
|
|
741
831
|
"""Manage custom attributes (coming soon)."""
|
|
@@ -753,6 +843,7 @@ def list_attributes():
|
|
|
753
843
|
# REQUESTS (Coming Soon)
|
|
754
844
|
# ========================================
|
|
755
845
|
|
|
846
|
+
|
|
756
847
|
@uc.group()
|
|
757
848
|
def request():
|
|
758
849
|
"""Manage access requests (coming soon)."""
|
|
@@ -763,4 +854,4 @@ def request():
|
|
|
763
854
|
def list_requests():
|
|
764
855
|
"""List access requests (coming soon)."""
|
|
765
856
|
console.print("[yellow]🚧 Access Requests are coming soon[/yellow]")
|
|
766
|
-
console.print("This feature is under development for data access workflows")
|
|
857
|
+
console.print("This feature is under development for data access workflows")
|