pvw-cli 1.0.6__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/cli.py +11 -13
- purviewcli/cli/collections.py +363 -0
- purviewcli/cli/entity.py +464 -0
- purviewcli/cli/unified_catalog.py +766 -0
- purviewcli/client/_search.py +7 -2
- purviewcli/client/_unified_catalog.py +258 -307
- purviewcli/client/endpoint.py +13 -1
- purviewcli/client/sync_client.py +70 -13
- {pvw_cli-1.0.6.dist-info → pvw_cli-1.0.8.dist-info}/METADATA +93 -34
- {pvw_cli-1.0.6.dist-info → pvw_cli-1.0.8.dist-info}/RECORD +15 -16
- {pvw_cli-1.0.6.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.6.dist-info → pvw_cli-1.0.8.dist-info}/entry_points.txt +0 -0
- {pvw_cli-1.0.6.dist-info → pvw_cli-1.0.8.dist-info}/top_level.txt +0 -0
purviewcli/cli/data_product.py
DELETED
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
import click
|
|
2
|
-
import csv
|
|
3
|
-
import json
|
|
4
|
-
import tempfile
|
|
5
|
-
import os
|
|
6
|
-
from rich.console import Console
|
|
7
|
-
from purviewcli.client._unified_catalog import UnifiedCatalogDataProduct
|
|
8
|
-
|
|
9
|
-
console = Console()
|
|
10
|
-
|
|
11
|
-
@click.group()
|
|
12
|
-
def data_product():
|
|
13
|
-
"""Manage data products in Microsoft Purview using Unified Catalog API."""
|
|
14
|
-
pass
|
|
15
|
-
|
|
16
|
-
@data_product.command()
|
|
17
|
-
@click.option('--name', required=True, help="Name of the data product")
|
|
18
|
-
@click.option('--description', required=False, help="Description of the data product")
|
|
19
|
-
@click.option('--domain-guid', required=False, help="GUID of the domain to associate with")
|
|
20
|
-
def create(name, description, domain_guid):
|
|
21
|
-
"""Create a new data product using Unified Catalog API."""
|
|
22
|
-
try:
|
|
23
|
-
data_product_client = UnifiedCatalogDataProduct()
|
|
24
|
-
result = data_product_client.create_data_product(
|
|
25
|
-
name=name,
|
|
26
|
-
description=description,
|
|
27
|
-
domain_guid=domain_guid
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
if result.get("status") == "error":
|
|
31
|
-
console.print(f"[red]ERROR:[/red] {result.get('message', 'Unknown error')}")
|
|
32
|
-
return
|
|
33
|
-
|
|
34
|
-
console.print(f"[green]SUCCESS:[/green] Created data product '{name}'")
|
|
35
|
-
console.print(json.dumps(result, indent=2))
|
|
36
|
-
|
|
37
|
-
except Exception as e:
|
|
38
|
-
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
39
|
-
|
|
40
|
-
@data_product.command()
|
|
41
|
-
@click.option('--data-product-id', required=True, help="ID of the data product")
|
|
42
|
-
def show(data_product_id):
|
|
43
|
-
"""Show details of a data product using Unified Catalog API."""
|
|
44
|
-
try:
|
|
45
|
-
data_product_client = UnifiedCatalogDataProduct()
|
|
46
|
-
result = data_product_client.get_data_product(data_product_id)
|
|
47
|
-
|
|
48
|
-
if result.get("status") == "error":
|
|
49
|
-
console.print(f"[red]ERROR:[/red] {result.get('message', 'Unknown error')}")
|
|
50
|
-
return
|
|
51
|
-
|
|
52
|
-
console.print(json.dumps(result, indent=2))
|
|
53
|
-
except Exception as e:
|
|
54
|
-
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
55
|
-
|
|
56
|
-
@data_product.command()
|
|
57
|
-
@click.option('--data-product-id', required=True, help="ID of the data product")
|
|
58
|
-
@click.option('--name', required=False, help="New name for the data product")
|
|
59
|
-
@click.option('--description', required=False, help="New description for the data product")
|
|
60
|
-
def update(data_product_id, name, description):
|
|
61
|
-
"""Update a data product using Unified Catalog API."""
|
|
62
|
-
try:
|
|
63
|
-
data_product_client = UnifiedCatalogDataProduct()
|
|
64
|
-
updates = {}
|
|
65
|
-
if name:
|
|
66
|
-
updates['name'] = name
|
|
67
|
-
if description:
|
|
68
|
-
updates['description'] = description
|
|
69
|
-
|
|
70
|
-
if not updates:
|
|
71
|
-
console.print("[yellow]WARNING:[/yellow] No updates specified")
|
|
72
|
-
return
|
|
73
|
-
|
|
74
|
-
result = data_product_client.update_data_product(data_product_id, updates)
|
|
75
|
-
|
|
76
|
-
if result.get("status") == "error":
|
|
77
|
-
console.print(f"[red]ERROR:[/red] {result.get('message', 'Unknown error')}")
|
|
78
|
-
return
|
|
79
|
-
|
|
80
|
-
console.print(f"[green]SUCCESS:[/green] Updated data product '{data_product_id}'")
|
|
81
|
-
console.print(json.dumps(result, indent=2))
|
|
82
|
-
|
|
83
|
-
except Exception as e:
|
|
84
|
-
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
85
|
-
|
|
86
|
-
@data_product.command()
|
|
87
|
-
@click.option('--data-product-id', required=True, help="ID of the data product")
|
|
88
|
-
def delete(data_product_id):
|
|
89
|
-
"""Delete a data product using Unified Catalog API."""
|
|
90
|
-
try:
|
|
91
|
-
data_product_client = UnifiedCatalogDataProduct()
|
|
92
|
-
result = data_product_client.delete_data_product(data_product_id)
|
|
93
|
-
|
|
94
|
-
if result.get("status") == "error":
|
|
95
|
-
console.print(f"[red]ERROR:[/red] {result.get('message', 'Unknown error')}")
|
|
96
|
-
return
|
|
97
|
-
|
|
98
|
-
console.print(f"[green]SUCCESS:[/green] Deleted data product '{data_product_id}'")
|
|
99
|
-
console.print(json.dumps(result, indent=2))
|
|
100
|
-
except Exception as e:
|
|
101
|
-
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
102
|
-
|
|
103
|
-
@data_product.command()
|
|
104
|
-
@click.option('--limit', default=50, help="Maximum number of data products to list")
|
|
105
|
-
@click.option('--skip', default=0, help="Number of data products to skip")
|
|
106
|
-
@click.option('--domain-id', required=False, help="Filter by governance domain ID")
|
|
107
|
-
def list(limit, skip, domain_id):
|
|
108
|
-
"""List data products using Unified Catalog API."""
|
|
109
|
-
try:
|
|
110
|
-
data_product_client = UnifiedCatalogDataProduct()
|
|
111
|
-
result = data_product_client.list_data_products(
|
|
112
|
-
limit=limit,
|
|
113
|
-
offset=skip,
|
|
114
|
-
domain_id=domain_id
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
if result.get("status") == "error":
|
|
118
|
-
console.print(f"[red]ERROR:[/red] {result.get('message', 'Unknown error')}")
|
|
119
|
-
return
|
|
120
|
-
|
|
121
|
-
console.print(json.dumps(result, indent=2))
|
|
122
|
-
except Exception as e:
|
|
123
|
-
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
124
|
-
|
|
125
|
-
@data_product.command()
|
|
126
|
-
@click.option('--data-product-id', required=True, help="ID of the data product")
|
|
127
|
-
def publish(data_product_id):
|
|
128
|
-
"""Publish a data product using Unified Catalog API."""
|
|
129
|
-
try:
|
|
130
|
-
data_product_client = UnifiedCatalogDataProduct()
|
|
131
|
-
result = data_product_client.update_data_product(data_product_id, {"status": "Published"})
|
|
132
|
-
|
|
133
|
-
if result.get("status") == "error":
|
|
134
|
-
console.print(f"[red]ERROR:[/red] {result.get('message', 'Unknown error')}")
|
|
135
|
-
return
|
|
136
|
-
|
|
137
|
-
console.print(f"[green]SUCCESS:[/green] Published data product '{data_product_id}'")
|
|
138
|
-
console.print(json.dumps(result, indent=2))
|
|
139
|
-
except Exception as e:
|
|
140
|
-
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
141
|
-
|
|
142
|
-
@data_product.command()
|
|
143
|
-
@click.option('--data-product-id', required=True, help="ID of the data product")
|
|
144
|
-
def unpublish(data_product_id):
|
|
145
|
-
"""Unpublish a data product using Unified Catalog API."""
|
|
146
|
-
try:
|
|
147
|
-
data_product_client = UnifiedCatalogDataProduct()
|
|
148
|
-
result = data_product_client.update_data_product(data_product_id, {"status": "Draft"})
|
|
149
|
-
|
|
150
|
-
if result.get("status") == "error":
|
|
151
|
-
console.print(f"[red]ERROR:[/red] {result.get('message', 'Unknown error')}")
|
|
152
|
-
return
|
|
153
|
-
|
|
154
|
-
console.print(f"[green]SUCCESS:[/green] Unpublished data product '{data_product_id}'")
|
|
155
|
-
console.print(json.dumps(result, indent=2))
|
|
156
|
-
except Exception as e:
|
|
157
|
-
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
158
|
-
|
|
159
|
-
# === BUSINESS DOMAIN COMMANDS ===
|
|
160
|
-
# Business domains are required for data product creation
|
|
161
|
-
|
|
162
|
-
@data_product.command()
|
|
163
|
-
def list_domains():
|
|
164
|
-
"""List all business domains."""
|
|
165
|
-
try:
|
|
166
|
-
data_product_client = UnifiedCatalogDataProduct()
|
|
167
|
-
result = data_product_client.businessDomainList({})
|
|
168
|
-
|
|
169
|
-
if result.get("status") == "error":
|
|
170
|
-
console.print(f"[red]ERROR:[/red] {result.get('message', 'Unknown error')}")
|
|
171
|
-
return
|
|
172
|
-
|
|
173
|
-
console.print(json.dumps(result, indent=2))
|
|
174
|
-
except Exception as e:
|
|
175
|
-
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
176
|
-
|
|
177
|
-
@data_product.command()
|
|
178
|
-
@click.option('--name', required=True, help="Name of the business domain")
|
|
179
|
-
@click.option('--description', required=False, help="Description of the business domain")
|
|
180
|
-
@click.option('--type', default="DataDomain", help="Type of the business domain (DataDomain, LineOfBusiness, etc.)")
|
|
181
|
-
def create_domain(name, description, type):
|
|
182
|
-
"""Create a new business domain."""
|
|
183
|
-
try:
|
|
184
|
-
data_product_client = UnifiedCatalogDataProduct()
|
|
185
|
-
args = {
|
|
186
|
-
"--name": name,
|
|
187
|
-
"--description": description or "",
|
|
188
|
-
"--type": type,
|
|
189
|
-
"--status": "Draft"
|
|
190
|
-
}
|
|
191
|
-
result = data_product_client.businessDomainCreate(args)
|
|
192
|
-
|
|
193
|
-
if result.get("status") == "error":
|
|
194
|
-
console.print(f"[red]ERROR:[/red] {result.get('message', 'Unknown error')}")
|
|
195
|
-
return
|
|
196
|
-
|
|
197
|
-
console.print(f"[green]SUCCESS:[/green] Created business domain '{name}'")
|
|
198
|
-
console.print(json.dumps(result, indent=2))
|
|
199
|
-
except Exception as e:
|
|
200
|
-
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
201
|
-
|
|
202
|
-
@data_product.command()
|
|
203
|
-
@click.option('--domain-id', required=True, help="ID of the business domain")
|
|
204
|
-
def show_domain(domain_id):
|
|
205
|
-
"""Show details of a business domain."""
|
|
206
|
-
try:
|
|
207
|
-
data_product_client = UnifiedCatalogDataProduct()
|
|
208
|
-
result = data_product_client.businessDomainRead({"--domainId": domain_id})
|
|
209
|
-
|
|
210
|
-
if result.get("status") == "error":
|
|
211
|
-
console.print(f"[red]ERROR:[/red] {result.get('message', 'Unknown error')}")
|
|
212
|
-
return
|
|
213
|
-
|
|
214
|
-
console.print(json.dumps(result, indent=2))
|
|
215
|
-
except Exception as e:
|
|
216
|
-
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
217
|
-
|
|
218
|
-
# === GLOSSARY TERM COMMANDS ===
|
|
219
|
-
|
|
220
|
-
@data_product.command()
|
|
221
|
-
@click.option('--domain-id', required=False, help="Filter by governance domain ID")
|
|
222
|
-
def list_terms(domain_id):
|
|
223
|
-
"""List glossary terms."""
|
|
224
|
-
try:
|
|
225
|
-
data_product_client = UnifiedCatalogDataProduct()
|
|
226
|
-
args = {}
|
|
227
|
-
if domain_id:
|
|
228
|
-
args["--governanceDomain"] = domain_id
|
|
229
|
-
result = data_product_client.glossaryTermsList(args)
|
|
230
|
-
|
|
231
|
-
if result.get("status") == "error":
|
|
232
|
-
console.print(f"[red]ERROR:[/red] {result.get('message', 'Unknown error')}")
|
|
233
|
-
return
|
|
234
|
-
|
|
235
|
-
console.print(json.dumps(result, indent=2))
|
|
236
|
-
except Exception as e:
|
|
237
|
-
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
238
|
-
|
|
239
|
-
@data_product.command()
|
|
240
|
-
@click.option('--name', required=True, help="Name of the glossary term")
|
|
241
|
-
@click.option('--description', required=False, help="Description of the glossary term")
|
|
242
|
-
@click.option('--domain-id', required=True, help="ID of the governance domain")
|
|
243
|
-
def create_term(name, description, domain_id):
|
|
244
|
-
"""Create a new glossary term."""
|
|
245
|
-
try:
|
|
246
|
-
data_product_client = UnifiedCatalogDataProduct()
|
|
247
|
-
result = data_product_client.create_glossary_term(
|
|
248
|
-
name=name,
|
|
249
|
-
description=description or "",
|
|
250
|
-
domain_id=domain_id
|
|
251
|
-
)
|
|
252
|
-
|
|
253
|
-
if result.get("status") == "error":
|
|
254
|
-
console.print(f"[red]ERROR:[/red] {result.get('message', 'Unknown error')}")
|
|
255
|
-
return
|
|
256
|
-
|
|
257
|
-
console.print(f"[green]SUCCESS:[/green] Created glossary term '{name}'")
|
|
258
|
-
console.print(json.dumps(result, indent=2))
|
|
259
|
-
except Exception as e:
|
|
260
|
-
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
261
|
-
|
|
262
|
-
@data_product.command()
|
|
263
|
-
@click.option('--data-product-id', required=True, help="ID of the data product")
|
|
264
|
-
@click.option('--term-id', required=True, help="ID of the glossary term")
|
|
265
|
-
def link_term(data_product_id, term_id):
|
|
266
|
-
"""Link a glossary term to a data product."""
|
|
267
|
-
try:
|
|
268
|
-
data_product_client = UnifiedCatalogDataProduct()
|
|
269
|
-
result = data_product_client.link_term_to_data_product(data_product_id, term_id)
|
|
270
|
-
|
|
271
|
-
if result.get("status") == "error":
|
|
272
|
-
console.print(f"[red]ERROR:[/red] {result.get('message', 'Unknown error')}")
|
|
273
|
-
return
|
|
274
|
-
|
|
275
|
-
console.print(f"[green]SUCCESS:[/green] Linked term '{term_id}' to data product '{data_product_id}'")
|
|
276
|
-
console.print(json.dumps(result, indent=2))
|
|
277
|
-
except Exception as e:
|
|
278
|
-
console.print(f"[red]ERROR:[/red] {str(e)}")
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import tempfile
|
|
3
|
-
import os
|
|
4
|
-
import csv
|
|
5
|
-
from purviewcli.client._entity import Entity
|
|
6
|
-
|
|
7
|
-
class DataProduct:
|
|
8
|
-
"""Client for managing data products in Microsoft Purview."""
|
|
9
|
-
|
|
10
|
-
def __init__(self):
|
|
11
|
-
self.entity_client = Entity()
|
|
12
|
-
|
|
13
|
-
def import_from_csv(self, products):
|
|
14
|
-
with open("import_from_csv_debug.log", "a") as logf:
|
|
15
|
-
logf.write(f"products type: {type(products)}\n")
|
|
16
|
-
if products:
|
|
17
|
-
logf.write(f"first product type: {type(products[0])}\n")
|
|
18
|
-
logf.write(f"first product: {products[0]}\n")
|
|
19
|
-
if not isinstance(products, list):
|
|
20
|
-
raise TypeError(f"Expected a list, got: {type(products)} with value: {products}")
|
|
21
|
-
if not products or not isinstance(products[0], dict):
|
|
22
|
-
raise TypeError(
|
|
23
|
-
f"Expected a list of dicts, got: {type(products[0])} with value: {products[0]}"
|
|
24
|
-
)
|
|
25
|
-
required_fields = ["qualifiedName"]
|
|
26
|
-
entities = []
|
|
27
|
-
for product in products:
|
|
28
|
-
# Validate required fields
|
|
29
|
-
for field in required_fields:
|
|
30
|
-
if not product.get(field):
|
|
31
|
-
raise ValueError(f"Missing required field '{field}' in row: {product}")
|
|
32
|
-
# Always use typeName DataSet (Purview default)
|
|
33
|
-
attributes = {k: v for k, v in product.items() if k != "typeName"}
|
|
34
|
-
entity = {
|
|
35
|
-
"typeName": "DataSet",
|
|
36
|
-
"attributes": attributes
|
|
37
|
-
}
|
|
38
|
-
entities.append(entity)
|
|
39
|
-
# Write the bulk payload to a temp file (always as {"entities": [...]})
|
|
40
|
-
bulk_payload = {"entities": entities}
|
|
41
|
-
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as tmpf:
|
|
42
|
-
json.dump(bulk_payload, tmpf, indent=2)
|
|
43
|
-
tmpf.flush()
|
|
44
|
-
payload_file = tmpf.name
|
|
45
|
-
try:
|
|
46
|
-
result = self.entity_client.entityCreateBulk({"--payloadFile": payload_file})
|
|
47
|
-
return [(e["attributes"]["qualifiedName"], result) for e in entities]
|
|
48
|
-
finally:
|
|
49
|
-
os.remove(payload_file)
|
|
50
|
-
|
|
51
|
-
def import_from_csv_file(self, csv_file_path, dry_run=False):
|
|
52
|
-
"""Load data products from a CSV file and import them. If dry_run is True, return the parsed products only."""
|
|
53
|
-
with open(csv_file_path, 'r', encoding='utf-8') as f:
|
|
54
|
-
reader = csv.DictReader(f)
|
|
55
|
-
products = list(reader)
|
|
56
|
-
if dry_run:
|
|
57
|
-
return products
|
|
58
|
-
return self.import_from_csv(products)
|
|
59
|
-
|
|
60
|
-
def create(self, qualified_name, name=None, description=None, type_name="DataProduct"):
|
|
61
|
-
"""Create a single data product entity."""
|
|
62
|
-
payload = {
|
|
63
|
-
"typeName": type_name,
|
|
64
|
-
"attributes": {
|
|
65
|
-
"qualifiedName": qualified_name,
|
|
66
|
-
"name": name or qualified_name,
|
|
67
|
-
"description": description or ""
|
|
68
|
-
},
|
|
69
|
-
}
|
|
70
|
-
# Write payload to temp file since entity client expects a file path
|
|
71
|
-
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as tmpf:
|
|
72
|
-
json.dump(payload, tmpf, indent=2)
|
|
73
|
-
tmpf.flush()
|
|
74
|
-
payload_file = tmpf.name
|
|
75
|
-
|
|
76
|
-
try:
|
|
77
|
-
return self.entity_client.entityCreate({"--payloadFile": payload_file})
|
|
78
|
-
finally:
|
|
79
|
-
os.remove(payload_file)
|
|
80
|
-
|
|
81
|
-
def list(self, type_name="DataProduct"):
|
|
82
|
-
"""List all data products (by typeName)."""
|
|
83
|
-
# Use the entity client's search method to find all entities of type DataProduct
|
|
84
|
-
search_args = {
|
|
85
|
-
"keywords": "*", # match all
|
|
86
|
-
"filter": {
|
|
87
|
-
"entityType": [type_name]
|
|
88
|
-
},
|
|
89
|
-
"limit": 100
|
|
90
|
-
}
|
|
91
|
-
# If the entity client has a search method, use it; otherwise, return empty list
|
|
92
|
-
if hasattr(self.entity_client, "search_entities"):
|
|
93
|
-
return self.entity_client.search_entities(search_args)
|
|
94
|
-
# No suitable fallback for listing all entities by type; return empty list
|
|
95
|
-
return []
|
|
96
|
-
|
|
97
|
-
def show(self, qualified_name, type_name="DataProduct"):
|
|
98
|
-
"""Show a data product by qualifiedName."""
|
|
99
|
-
args = {"--typeName": type_name, "--qualifiedName": qualified_name}
|
|
100
|
-
return self.entity_client.entityReadUniqueAttribute(args)
|
|
101
|
-
|
|
102
|
-
def delete(self, qualified_name, type_name="DataProduct"):
|
|
103
|
-
"""Delete a data product by qualifiedName."""
|
|
104
|
-
args = {"--typeName": type_name, "--qualifiedName": qualified_name}
|
|
105
|
-
return self.entity_client.entityDeleteUniqueAttribute(args)
|
|
106
|
-
|
|
107
|
-
def add_classification(self, qualified_name, classification, type_name="DataProduct"):
|
|
108
|
-
"""Add a classification to a data product."""
|
|
109
|
-
args = {
|
|
110
|
-
"--typeName": type_name,
|
|
111
|
-
"--qualifiedName": qualified_name,
|
|
112
|
-
"--payloadFile": {"classifications": [classification]}
|
|
113
|
-
}
|
|
114
|
-
return self.entity_client.entityAddClassificationsByUniqueAttribute(args)
|
|
115
|
-
|
|
116
|
-
def remove_classification(self, qualified_name, classification, type_name="DataProduct"):
|
|
117
|
-
"""Remove a classification from a data product."""
|
|
118
|
-
args = {
|
|
119
|
-
"--typeName": type_name,
|
|
120
|
-
"--qualifiedName": qualified_name,
|
|
121
|
-
"--classificationName": classification
|
|
122
|
-
}
|
|
123
|
-
return self.entity_client.entityDeleteClassificationByUniqueAttribute(args)
|
|
124
|
-
|
|
125
|
-
def add_label(self, qualified_name, label, type_name="DataProduct"):
|
|
126
|
-
"""Add a label to a data product."""
|
|
127
|
-
args = {
|
|
128
|
-
"--typeName": type_name,
|
|
129
|
-
"--qualifiedName": qualified_name,
|
|
130
|
-
"--payloadFile": {"labels": [label]}
|
|
131
|
-
}
|
|
132
|
-
return self.entity_client.entityAddLabelsByUniqueAttribute(args)
|
|
133
|
-
|
|
134
|
-
def remove_label(self, qualified_name, label, type_name="DataProduct"):
|
|
135
|
-
"""Remove a label from a data product."""
|
|
136
|
-
args = {
|
|
137
|
-
"--typeName": type_name,
|
|
138
|
-
"--qualifiedName": qualified_name,
|
|
139
|
-
"--payloadFile": {"labels": [label]}
|
|
140
|
-
}
|
|
141
|
-
return self.entity_client.entityRemoveLabelsByUniqueAttribute(args)
|
|
142
|
-
|
|
143
|
-
def link_glossary(self, qualified_name, term, type_name="DataProduct"):
|
|
144
|
-
"""Link a glossary term to a data product."""
|
|
145
|
-
# This assumes business metadata or a custom attribute for glossary terms
|
|
146
|
-
# You may need to adjust this to your Purview model
|
|
147
|
-
args = {
|
|
148
|
-
"--typeName": type_name,
|
|
149
|
-
"--qualifiedName": qualified_name,
|
|
150
|
-
"--payloadFile": {"meanings": [term]}
|
|
151
|
-
}
|
|
152
|
-
return self.entity_client.entityPartialUpdateByUniqueAttribute(args)
|
|
153
|
-
|
|
154
|
-
def show_lineage(self, qualified_name, type_name="DataProduct"):
|
|
155
|
-
"""Show lineage for a data product."""
|
|
156
|
-
args = {"--typeName": type_name, "--qualifiedName": qualified_name}
|
|
157
|
-
# This assumes you have a lineage client or can call entityReadUniqueAttribute and extract lineage
|
|
158
|
-
# For now, just return the entity details
|
|
159
|
-
return self.entity_client.entityReadUniqueAttribute(args)
|
|
160
|
-
|
|
161
|
-
def set_status(self, qualified_name, status, type_name="DataProduct"):
|
|
162
|
-
"""Set the status of a data product (e.g., active, deprecated)."""
|
|
163
|
-
args = {
|
|
164
|
-
"--typeName": type_name,
|
|
165
|
-
"--qualifiedName": qualified_name,
|
|
166
|
-
"--payloadFile": {"status": status}
|
|
167
|
-
}
|
|
168
|
-
return self.entity_client.entityPartialUpdateByUniqueAttribute(args)
|
|
File without changes
|
|
File without changes
|