entropy-data 0.3.0__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.
- entropy_data/__init__.py +5 -0
- entropy_data/__main__.py +3 -0
- entropy_data/cli.py +133 -0
- entropy_data/client.py +163 -0
- entropy_data/commands/__init__.py +0 -0
- entropy_data/commands/access.py +128 -0
- entropy_data/commands/api_keys.py +65 -0
- entropy_data/commands/assets.py +80 -0
- entropy_data/commands/certifications.py +80 -0
- entropy_data/commands/connection.py +90 -0
- entropy_data/commands/costs.py +61 -0
- entropy_data/commands/datacontracts.py +115 -0
- entropy_data/commands/dataproducts.py +93 -0
- entropy_data/commands/definitions.py +80 -0
- entropy_data/commands/events.py +32 -0
- entropy_data/commands/example_data.py +83 -0
- entropy_data/commands/import_export.py +134 -0
- entropy_data/commands/lineage.py +107 -0
- entropy_data/commands/search.py +55 -0
- entropy_data/commands/settings.py +68 -0
- entropy_data/commands/sourcesystems.py +80 -0
- entropy_data/commands/tags.py +84 -0
- entropy_data/commands/teams.py +80 -0
- entropy_data/commands/test_results.py +85 -0
- entropy_data/commands/usage.py +99 -0
- entropy_data/config.py +141 -0
- entropy_data/output.py +119 -0
- entropy_data/util.py +22 -0
- entropy_data-0.3.0.dist-info/METADATA +23 -0
- entropy_data-0.3.0.dist-info/RECORD +33 -0
- entropy_data-0.3.0.dist-info/WHEEL +4 -0
- entropy_data-0.3.0.dist-info/entry_points.txt +2 -0
- entropy_data-0.3.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""Lineage commands (OpenLineage events)."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Annotated, Optional
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
|
|
9
|
+
from entropy_data.output import OutputFormat, console, print_resource_list, print_success
|
|
10
|
+
from entropy_data.util import read_body
|
|
11
|
+
|
|
12
|
+
lineage_app = typer.Typer(no_args_is_help=True)
|
|
13
|
+
RESOURCE_PATH = "v1/lineage"
|
|
14
|
+
RESOURCE_TYPE = "lineage"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@lineage_app.command("list")
|
|
18
|
+
def list_lineage(
|
|
19
|
+
job_namespace: Annotated[Optional[str], typer.Option("--job-namespace", help="Filter by job namespace.")] = None,
|
|
20
|
+
job_name: Annotated[Optional[str], typer.Option("--job-name", help="Filter by job name.")] = None,
|
|
21
|
+
run_id: Annotated[Optional[str], typer.Option("--run-id", help="Filter by run ID.")] = None,
|
|
22
|
+
event_type: Annotated[
|
|
23
|
+
Optional[str],
|
|
24
|
+
typer.Option("--event-type", help="Filter by event type (START, RUNNING, COMPLETE, ABORT, FAIL)."),
|
|
25
|
+
] = None,
|
|
26
|
+
data_product_id: Annotated[
|
|
27
|
+
Optional[str], typer.Option("--data-product-id", help="Filter by data product ID.")
|
|
28
|
+
] = None,
|
|
29
|
+
output: Annotated[Optional[OutputFormat], typer.Option("--output", "-o", help="Output format.")] = None,
|
|
30
|
+
) -> None:
|
|
31
|
+
"""List OpenLineage events."""
|
|
32
|
+
from entropy_data.cli import get_client, get_output_format, handle_error
|
|
33
|
+
|
|
34
|
+
fmt = output or get_output_format()
|
|
35
|
+
try:
|
|
36
|
+
params = {}
|
|
37
|
+
if job_namespace:
|
|
38
|
+
params["jobNamespace"] = job_namespace
|
|
39
|
+
if job_name:
|
|
40
|
+
params["jobName"] = job_name
|
|
41
|
+
if run_id:
|
|
42
|
+
params["runId"] = run_id
|
|
43
|
+
if event_type:
|
|
44
|
+
params["eventType"] = event_type
|
|
45
|
+
if data_product_id:
|
|
46
|
+
params["dataProductId"] = data_product_id
|
|
47
|
+
client = get_client()
|
|
48
|
+
data, _ = client.list_resources(RESOURCE_PATH, params=params)
|
|
49
|
+
if fmt == OutputFormat.json:
|
|
50
|
+
console.print_json(json.dumps(data))
|
|
51
|
+
else:
|
|
52
|
+
print_resource_list(data, RESOURCE_TYPE, fmt)
|
|
53
|
+
except Exception as e:
|
|
54
|
+
handle_error(e)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@lineage_app.command("submit")
|
|
58
|
+
def submit_lineage(
|
|
59
|
+
file: Annotated[
|
|
60
|
+
Path, typer.Option("--file", "-f", help="JSON or YAML file with OpenLineage RunEvent (use - for stdin).")
|
|
61
|
+
] = ...,
|
|
62
|
+
data_product_id: Annotated[
|
|
63
|
+
Optional[str], typer.Option("--data-product-id", help="Data product ID to associate the event with.")
|
|
64
|
+
] = None,
|
|
65
|
+
output_port_name: Annotated[
|
|
66
|
+
Optional[str], typer.Option("--output-port-name", help="Output port name within the data product.")
|
|
67
|
+
] = None,
|
|
68
|
+
) -> None:
|
|
69
|
+
"""Submit an OpenLineage RunEvent."""
|
|
70
|
+
from entropy_data.cli import get_client, handle_error
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
body = read_body(file)
|
|
74
|
+
params = {}
|
|
75
|
+
if data_product_id:
|
|
76
|
+
params["dataProductId"] = data_product_id
|
|
77
|
+
if output_port_name:
|
|
78
|
+
params["outputPortName"] = output_port_name
|
|
79
|
+
client = get_client()
|
|
80
|
+
client.post_resource(RESOURCE_PATH, body, params=params or None)
|
|
81
|
+
print_success("Lineage event submitted.")
|
|
82
|
+
except Exception as e:
|
|
83
|
+
handle_error(e)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@lineage_app.command("delete")
|
|
87
|
+
def delete_lineage(
|
|
88
|
+
run_id: Annotated[Optional[str], typer.Option("--run-id", help="Delete by run ID.")] = None,
|
|
89
|
+
job_namespace: Annotated[Optional[str], typer.Option("--job-namespace", help="Delete by job namespace.")] = None,
|
|
90
|
+
job_name: Annotated[Optional[str], typer.Option("--job-name", help="Delete by job name.")] = None,
|
|
91
|
+
) -> None:
|
|
92
|
+
"""Delete OpenLineage events."""
|
|
93
|
+
from entropy_data.cli import get_client, handle_error
|
|
94
|
+
|
|
95
|
+
try:
|
|
96
|
+
params = {}
|
|
97
|
+
if run_id:
|
|
98
|
+
params["runId"] = run_id
|
|
99
|
+
if job_namespace:
|
|
100
|
+
params["jobNamespace"] = job_namespace
|
|
101
|
+
if job_name:
|
|
102
|
+
params["jobName"] = job_name
|
|
103
|
+
client = get_client()
|
|
104
|
+
client.delete_resources(RESOURCE_PATH, params=params or None)
|
|
105
|
+
print_success("Lineage events deleted.")
|
|
106
|
+
except Exception as e:
|
|
107
|
+
handle_error(e)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Search commands."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Annotated, Optional
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from entropy_data.output import OutputFormat, console
|
|
9
|
+
|
|
10
|
+
search_app = typer.Typer(no_args_is_help=True)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@search_app.command("query")
|
|
14
|
+
def search_query(
|
|
15
|
+
query: Annotated[str, typer.Argument(help="Search query.")],
|
|
16
|
+
resource_type: Annotated[
|
|
17
|
+
Optional[str], typer.Option("--resource-type", "-t", help="Filter by resource type.")
|
|
18
|
+
] = None,
|
|
19
|
+
output: Annotated[Optional[OutputFormat], typer.Option("--output", "-o", help="Output format.")] = None,
|
|
20
|
+
) -> None:
|
|
21
|
+
"""Search across all resources."""
|
|
22
|
+
from entropy_data.cli import get_client, get_output_format, handle_error
|
|
23
|
+
|
|
24
|
+
fmt = output or get_output_format()
|
|
25
|
+
try:
|
|
26
|
+
client = get_client()
|
|
27
|
+
params = {}
|
|
28
|
+
if resource_type:
|
|
29
|
+
params["resourceType"] = resource_type
|
|
30
|
+
data = client.search(query, **params)
|
|
31
|
+
|
|
32
|
+
if fmt == OutputFormat.json:
|
|
33
|
+
console.print_json(json.dumps(data))
|
|
34
|
+
return
|
|
35
|
+
|
|
36
|
+
# Table output for search results
|
|
37
|
+
results = data if isinstance(data, list) else data.get("results", data.get("items", [data]))
|
|
38
|
+
if isinstance(results, list):
|
|
39
|
+
from rich.table import Table
|
|
40
|
+
|
|
41
|
+
table = Table(show_header=True, title="Search Results")
|
|
42
|
+
table.add_column("Type")
|
|
43
|
+
table.add_column("ID")
|
|
44
|
+
table.add_column("Title")
|
|
45
|
+
for item in results:
|
|
46
|
+
table.add_row(
|
|
47
|
+
str(item.get("resourceType", item.get("type", ""))),
|
|
48
|
+
str(item.get("id", "")),
|
|
49
|
+
str(item.get("title", item.get("name", ""))),
|
|
50
|
+
)
|
|
51
|
+
console.print(table)
|
|
52
|
+
else:
|
|
53
|
+
console.print_json(json.dumps(data))
|
|
54
|
+
except Exception as e:
|
|
55
|
+
handle_error(e)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Settings commands."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Annotated, Optional
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
|
|
10
|
+
from entropy_data.output import OutputFormat, console, print_success
|
|
11
|
+
|
|
12
|
+
settings_app = typer.Typer(no_args_is_help=True)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@settings_app.command("get-customization")
|
|
16
|
+
def get_customization(
|
|
17
|
+
output: Annotated[Optional[OutputFormat], typer.Option("--output", "-o", help="Output format.")] = None,
|
|
18
|
+
) -> None:
|
|
19
|
+
"""Get organization customization settings."""
|
|
20
|
+
from entropy_data.cli import get_client, get_output_format, handle_error
|
|
21
|
+
from entropy_data.client import REQUEST_TIMEOUT, _raise_for_status
|
|
22
|
+
|
|
23
|
+
fmt = output or get_output_format()
|
|
24
|
+
try:
|
|
25
|
+
client = get_client()
|
|
26
|
+
accept = "application/json" if fmt == OutputFormat.json else "application/yaml"
|
|
27
|
+
response = client.session.get(
|
|
28
|
+
f"{client.base_url}/api/settings/customization",
|
|
29
|
+
headers={"Accept": accept},
|
|
30
|
+
timeout=REQUEST_TIMEOUT,
|
|
31
|
+
)
|
|
32
|
+
_raise_for_status(response)
|
|
33
|
+
if fmt == OutputFormat.json:
|
|
34
|
+
console.print_json(json.dumps(response.json()))
|
|
35
|
+
else:
|
|
36
|
+
console.print(response.text)
|
|
37
|
+
except Exception as e:
|
|
38
|
+
handle_error(e)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@settings_app.command("put-customization")
|
|
42
|
+
def put_customization(
|
|
43
|
+
file: Annotated[Path, typer.Option("--file", "-f", help="YAML or JSON file (use - for stdin).")] = ...,
|
|
44
|
+
) -> None:
|
|
45
|
+
"""Update organization customization settings."""
|
|
46
|
+
from entropy_data.cli import get_client, handle_error
|
|
47
|
+
from entropy_data.client import REQUEST_TIMEOUT, _raise_for_status
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
if str(file) == "-":
|
|
51
|
+
content = sys.stdin.read()
|
|
52
|
+
else:
|
|
53
|
+
content = file.read_text()
|
|
54
|
+
|
|
55
|
+
client = get_client()
|
|
56
|
+
# Detect content type from file extension or content
|
|
57
|
+
is_json = str(file).endswith(".json") or content.lstrip().startswith("{")
|
|
58
|
+
content_type = "application/json" if is_json else "application/yaml"
|
|
59
|
+
response = client.session.put(
|
|
60
|
+
f"{client.base_url}/api/settings/customization",
|
|
61
|
+
data=content.encode(),
|
|
62
|
+
headers={"Content-Type": content_type},
|
|
63
|
+
timeout=REQUEST_TIMEOUT,
|
|
64
|
+
)
|
|
65
|
+
_raise_for_status(response)
|
|
66
|
+
print_success("Customization updated.")
|
|
67
|
+
except Exception as e:
|
|
68
|
+
handle_error(e)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""Source systems commands."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Annotated, Optional
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from entropy_data.output import OutputFormat, print_link, print_resource, print_resource_list, print_success
|
|
9
|
+
from entropy_data.util import read_body
|
|
10
|
+
|
|
11
|
+
sourcesystems_app = typer.Typer(no_args_is_help=True)
|
|
12
|
+
RESOURCE_PATH = "sourcesystems"
|
|
13
|
+
RESOURCE_TYPE = "sourcesystems"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@sourcesystems_app.command("list")
|
|
17
|
+
def list_sourcesystems(
|
|
18
|
+
page: Annotated[int, typer.Option("--page", "-p", help="Page number (0-indexed).")] = 0,
|
|
19
|
+
output: Annotated[Optional[OutputFormat], typer.Option("--output", "-o", help="Output format.")] = None,
|
|
20
|
+
) -> None:
|
|
21
|
+
"""List all source systems."""
|
|
22
|
+
from entropy_data.cli import get_client, get_output_format, handle_error
|
|
23
|
+
|
|
24
|
+
fmt = output or get_output_format()
|
|
25
|
+
try:
|
|
26
|
+
client = get_client()
|
|
27
|
+
data, has_next = client.list_resources(RESOURCE_PATH, params={"p": page})
|
|
28
|
+
print_resource_list(data, RESOURCE_TYPE, fmt, has_next_page=has_next, page=page)
|
|
29
|
+
except Exception as e:
|
|
30
|
+
handle_error(e)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@sourcesystems_app.command("get")
|
|
34
|
+
def get_sourcesystem(
|
|
35
|
+
id: Annotated[str, typer.Argument(help="Source system ID.")],
|
|
36
|
+
output: Annotated[Optional[OutputFormat], typer.Option("--output", "-o", help="Output format.")] = None,
|
|
37
|
+
) -> None:
|
|
38
|
+
"""Get a source system by ID."""
|
|
39
|
+
from entropy_data.cli import get_client, get_output_format, handle_error
|
|
40
|
+
|
|
41
|
+
fmt = output or get_output_format()
|
|
42
|
+
try:
|
|
43
|
+
client = get_client()
|
|
44
|
+
data = client.get_resource(RESOURCE_PATH, id)
|
|
45
|
+
print_resource(data, RESOURCE_TYPE, fmt)
|
|
46
|
+
except Exception as e:
|
|
47
|
+
handle_error(e)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@sourcesystems_app.command("put")
|
|
51
|
+
def put_sourcesystem(
|
|
52
|
+
id: Annotated[str, typer.Argument(help="Source system ID.")],
|
|
53
|
+
file: Annotated[Path, typer.Option("--file", "-f", help="JSON or YAML file (use - for stdin).")] = ...,
|
|
54
|
+
) -> None:
|
|
55
|
+
"""Create or update a source system."""
|
|
56
|
+
from entropy_data.cli import get_client, handle_error
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
body = read_body(file)
|
|
60
|
+
client = get_client()
|
|
61
|
+
location = client.put_resource(RESOURCE_PATH, id, body)
|
|
62
|
+
print_success(f"Source system '{id}' saved.")
|
|
63
|
+
print_link(location)
|
|
64
|
+
except Exception as e:
|
|
65
|
+
handle_error(e)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@sourcesystems_app.command("delete")
|
|
69
|
+
def delete_sourcesystem(
|
|
70
|
+
id: Annotated[str, typer.Argument(help="Source system ID.")],
|
|
71
|
+
) -> None:
|
|
72
|
+
"""Delete a source system."""
|
|
73
|
+
from entropy_data.cli import get_client, handle_error
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
client = get_client()
|
|
77
|
+
client.delete_resource(RESOURCE_PATH, id)
|
|
78
|
+
print_success(f"Source system '{id}' deleted.")
|
|
79
|
+
except Exception as e:
|
|
80
|
+
handle_error(e)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""Tags commands."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Annotated, Optional
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from entropy_data.output import OutputFormat, print_link, print_resource, print_resource_list, print_success
|
|
9
|
+
from entropy_data.util import read_body
|
|
10
|
+
|
|
11
|
+
tags_app = typer.Typer(no_args_is_help=True)
|
|
12
|
+
RESOURCE_PATH = "tags"
|
|
13
|
+
RESOURCE_TYPE = "tags"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@tags_app.command("list")
|
|
17
|
+
def list_tags(
|
|
18
|
+
page: Annotated[int, typer.Option("--page", "-p", help="Page number (0-indexed).")] = 0,
|
|
19
|
+
owner: Annotated[Optional[str], typer.Option("--owner", help="Filter by owner (team name).")] = None,
|
|
20
|
+
output: Annotated[Optional[OutputFormat], typer.Option("--output", "-o", help="Output format.")] = None,
|
|
21
|
+
) -> None:
|
|
22
|
+
"""List all tags."""
|
|
23
|
+
from entropy_data.cli import get_client, get_output_format, handle_error
|
|
24
|
+
|
|
25
|
+
fmt = output or get_output_format()
|
|
26
|
+
try:
|
|
27
|
+
params = {"p": page}
|
|
28
|
+
if owner:
|
|
29
|
+
params["owner"] = owner
|
|
30
|
+
client = get_client()
|
|
31
|
+
data, has_next = client.list_resources(RESOURCE_PATH, params=params)
|
|
32
|
+
print_resource_list(data, RESOURCE_TYPE, fmt, has_next_page=has_next, page=page)
|
|
33
|
+
except Exception as e:
|
|
34
|
+
handle_error(e)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@tags_app.command("get")
|
|
38
|
+
def get_tag(
|
|
39
|
+
id: Annotated[str, typer.Argument(help="Tag ID (e.g. 'Governance/PII').")],
|
|
40
|
+
output: Annotated[Optional[OutputFormat], typer.Option("--output", "-o", help="Output format.")] = None,
|
|
41
|
+
) -> None:
|
|
42
|
+
"""Get a tag by ID."""
|
|
43
|
+
from entropy_data.cli import get_client, get_output_format, handle_error
|
|
44
|
+
|
|
45
|
+
fmt = output or get_output_format()
|
|
46
|
+
try:
|
|
47
|
+
client = get_client()
|
|
48
|
+
data = client.get_resource(RESOURCE_PATH, id)
|
|
49
|
+
print_resource(data, RESOURCE_TYPE, fmt)
|
|
50
|
+
except Exception as e:
|
|
51
|
+
handle_error(e)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@tags_app.command("put")
|
|
55
|
+
def put_tag(
|
|
56
|
+
id: Annotated[str, typer.Argument(help="Tag ID (e.g. 'Governance/PII').")],
|
|
57
|
+
file: Annotated[Path, typer.Option("--file", "-f", help="JSON or YAML file (use - for stdin).")] = ...,
|
|
58
|
+
) -> None:
|
|
59
|
+
"""Create or update a tag."""
|
|
60
|
+
from entropy_data.cli import get_client, handle_error
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
body = read_body(file)
|
|
64
|
+
client = get_client()
|
|
65
|
+
location = client.put_resource(RESOURCE_PATH, id, body)
|
|
66
|
+
print_success(f"Tag '{id}' saved.")
|
|
67
|
+
print_link(location)
|
|
68
|
+
except Exception as e:
|
|
69
|
+
handle_error(e)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@tags_app.command("delete")
|
|
73
|
+
def delete_tag(
|
|
74
|
+
id: Annotated[str, typer.Argument(help="Tag ID (e.g. 'Governance/PII').")],
|
|
75
|
+
) -> None:
|
|
76
|
+
"""Delete a tag."""
|
|
77
|
+
from entropy_data.cli import get_client, handle_error
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
client = get_client()
|
|
81
|
+
client.delete_resource(RESOURCE_PATH, id)
|
|
82
|
+
print_success(f"Tag '{id}' deleted.")
|
|
83
|
+
except Exception as e:
|
|
84
|
+
handle_error(e)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""Teams commands."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Annotated, Optional
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from entropy_data.output import OutputFormat, print_link, print_resource, print_resource_list, print_success
|
|
9
|
+
from entropy_data.util import read_body
|
|
10
|
+
|
|
11
|
+
teams_app = typer.Typer(no_args_is_help=True)
|
|
12
|
+
RESOURCE_PATH = "teams"
|
|
13
|
+
RESOURCE_TYPE = "teams"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@teams_app.command("list")
|
|
17
|
+
def list_teams(
|
|
18
|
+
page: Annotated[int, typer.Option("--page", "-p", help="Page number (0-indexed).")] = 0,
|
|
19
|
+
output: Annotated[Optional[OutputFormat], typer.Option("--output", "-o", help="Output format.")] = None,
|
|
20
|
+
) -> None:
|
|
21
|
+
"""List all teams."""
|
|
22
|
+
from entropy_data.cli import get_client, get_output_format, handle_error
|
|
23
|
+
|
|
24
|
+
fmt = output or get_output_format()
|
|
25
|
+
try:
|
|
26
|
+
client = get_client()
|
|
27
|
+
data, has_next = client.list_resources(RESOURCE_PATH, params={"p": page})
|
|
28
|
+
print_resource_list(data, RESOURCE_TYPE, fmt, has_next_page=has_next, page=page)
|
|
29
|
+
except Exception as e:
|
|
30
|
+
handle_error(e)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@teams_app.command("get")
|
|
34
|
+
def get_team(
|
|
35
|
+
id: Annotated[str, typer.Argument(help="Team ID.")],
|
|
36
|
+
output: Annotated[Optional[OutputFormat], typer.Option("--output", "-o", help="Output format.")] = None,
|
|
37
|
+
) -> None:
|
|
38
|
+
"""Get a team by ID."""
|
|
39
|
+
from entropy_data.cli import get_client, get_output_format, handle_error
|
|
40
|
+
|
|
41
|
+
fmt = output or get_output_format()
|
|
42
|
+
try:
|
|
43
|
+
client = get_client()
|
|
44
|
+
data = client.get_resource(RESOURCE_PATH, id)
|
|
45
|
+
print_resource(data, RESOURCE_TYPE, fmt)
|
|
46
|
+
except Exception as e:
|
|
47
|
+
handle_error(e)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@teams_app.command("put")
|
|
51
|
+
def put_team(
|
|
52
|
+
id: Annotated[str, typer.Argument(help="Team ID.")],
|
|
53
|
+
file: Annotated[Path, typer.Option("--file", "-f", help="JSON or YAML file (use - for stdin).")] = ...,
|
|
54
|
+
) -> None:
|
|
55
|
+
"""Create or update a team."""
|
|
56
|
+
from entropy_data.cli import get_client, handle_error
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
body = read_body(file)
|
|
60
|
+
client = get_client()
|
|
61
|
+
location = client.put_resource(RESOURCE_PATH, id, body)
|
|
62
|
+
print_success(f"Team '{id}' saved.")
|
|
63
|
+
print_link(location)
|
|
64
|
+
except Exception as e:
|
|
65
|
+
handle_error(e)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@teams_app.command("delete")
|
|
69
|
+
def delete_team(
|
|
70
|
+
id: Annotated[str, typer.Argument(help="Team ID.")],
|
|
71
|
+
) -> None:
|
|
72
|
+
"""Delete a team."""
|
|
73
|
+
from entropy_data.cli import get_client, handle_error
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
client = get_client()
|
|
77
|
+
client.delete_resource(RESOURCE_PATH, id)
|
|
78
|
+
print_success(f"Team '{id}' deleted.")
|
|
79
|
+
except Exception as e:
|
|
80
|
+
handle_error(e)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""Test results commands."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Annotated, Optional
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from entropy_data.output import OutputFormat, print_link, print_resource, print_resource_list, print_success
|
|
9
|
+
from entropy_data.util import read_body
|
|
10
|
+
|
|
11
|
+
test_results_app = typer.Typer(no_args_is_help=True)
|
|
12
|
+
RESOURCE_PATH = "test-results"
|
|
13
|
+
RESOURCE_TYPE = "test-results"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@test_results_app.command("list")
|
|
17
|
+
def list_test_results(
|
|
18
|
+
page: Annotated[int, typer.Option("--page", "-p", help="Page number (0-indexed).")] = 0,
|
|
19
|
+
data_contract_id: Annotated[
|
|
20
|
+
Optional[str], typer.Option("--data-contract-id", help="Filter by data contract.")
|
|
21
|
+
] = None,
|
|
22
|
+
output: Annotated[Optional[OutputFormat], typer.Option("--output", "-o", help="Output format.")] = None,
|
|
23
|
+
) -> None:
|
|
24
|
+
"""List all test results."""
|
|
25
|
+
from entropy_data.cli import get_client, get_output_format, handle_error
|
|
26
|
+
|
|
27
|
+
fmt = output or get_output_format()
|
|
28
|
+
try:
|
|
29
|
+
client = get_client()
|
|
30
|
+
params = {"p": page}
|
|
31
|
+
if data_contract_id:
|
|
32
|
+
params["dataContractId"] = data_contract_id
|
|
33
|
+
data, has_next = client.list_resources(RESOURCE_PATH, params=params)
|
|
34
|
+
print_resource_list(data, RESOURCE_TYPE, fmt, has_next_page=has_next, page=page)
|
|
35
|
+
except Exception as e:
|
|
36
|
+
handle_error(e)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@test_results_app.command("get")
|
|
40
|
+
def get_test_result(
|
|
41
|
+
id: Annotated[str, typer.Argument(help="Test result ID.")],
|
|
42
|
+
output: Annotated[Optional[OutputFormat], typer.Option("--output", "-o", help="Output format.")] = None,
|
|
43
|
+
) -> None:
|
|
44
|
+
"""Get a test result by ID."""
|
|
45
|
+
from entropy_data.cli import get_client, get_output_format, handle_error
|
|
46
|
+
|
|
47
|
+
fmt = output or get_output_format()
|
|
48
|
+
try:
|
|
49
|
+
client = get_client()
|
|
50
|
+
data = client.get_resource(RESOURCE_PATH, id)
|
|
51
|
+
print_resource(data, RESOURCE_TYPE, fmt)
|
|
52
|
+
except Exception as e:
|
|
53
|
+
handle_error(e)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@test_results_app.command("publish")
|
|
57
|
+
def publish_test_results(
|
|
58
|
+
file: Annotated[Path, typer.Option("--file", "-f", help="JSON or YAML file (use - for stdin).")] = ...,
|
|
59
|
+
) -> None:
|
|
60
|
+
"""Publish test results."""
|
|
61
|
+
from entropy_data.cli import get_client, handle_error
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
body = read_body(file)
|
|
65
|
+
client = get_client()
|
|
66
|
+
location = client.post_resource(RESOURCE_PATH, body)
|
|
67
|
+
print_success("Test results published.")
|
|
68
|
+
print_link(location)
|
|
69
|
+
except Exception as e:
|
|
70
|
+
handle_error(e)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@test_results_app.command("delete")
|
|
74
|
+
def delete_test_result(
|
|
75
|
+
id: Annotated[str, typer.Argument(help="Test result ID.")],
|
|
76
|
+
) -> None:
|
|
77
|
+
"""Delete a test result."""
|
|
78
|
+
from entropy_data.cli import get_client, handle_error
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
client = get_client()
|
|
82
|
+
client.delete_resource(RESOURCE_PATH, id)
|
|
83
|
+
print_success(f"Test result '{id}' deleted.")
|
|
84
|
+
except Exception as e:
|
|
85
|
+
handle_error(e)
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""Usage commands (OpenTelemetry traces)."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Annotated, Optional
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
|
|
9
|
+
from entropy_data.output import OutputFormat, console, print_resource_list, print_success
|
|
10
|
+
from entropy_data.util import read_body
|
|
11
|
+
|
|
12
|
+
usage_app = typer.Typer(no_args_is_help=True)
|
|
13
|
+
RESOURCE_PATH = "v1/traces"
|
|
14
|
+
RESOURCE_TYPE = "usage"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@usage_app.command("list")
|
|
18
|
+
def list_usage(
|
|
19
|
+
scope_name: Annotated[
|
|
20
|
+
Optional[str], typer.Option("--scope-name", help="Filter by scope name (e.g., 'usage').")
|
|
21
|
+
] = None,
|
|
22
|
+
data_product_id: Annotated[
|
|
23
|
+
Optional[str], typer.Option("--data-product-id", help="Filter by data product ID.")
|
|
24
|
+
] = None,
|
|
25
|
+
data_contract_id: Annotated[
|
|
26
|
+
Optional[str], typer.Option("--data-contract-id", help="Filter by data contract ID.")
|
|
27
|
+
] = None,
|
|
28
|
+
output: Annotated[Optional[OutputFormat], typer.Option("--output", "-o", help="Output format.")] = None,
|
|
29
|
+
) -> None:
|
|
30
|
+
"""List usage traces."""
|
|
31
|
+
from entropy_data.cli import get_client, get_output_format, handle_error
|
|
32
|
+
|
|
33
|
+
fmt = output or get_output_format()
|
|
34
|
+
try:
|
|
35
|
+
params = {}
|
|
36
|
+
if scope_name:
|
|
37
|
+
params["scopeName"] = scope_name
|
|
38
|
+
if data_product_id:
|
|
39
|
+
params["dataProductId"] = data_product_id
|
|
40
|
+
if data_contract_id:
|
|
41
|
+
params["dataContractId"] = data_contract_id
|
|
42
|
+
client = get_client()
|
|
43
|
+
data, _ = client.list_resources(RESOURCE_PATH, params=params)
|
|
44
|
+
if fmt == OutputFormat.json:
|
|
45
|
+
console.print_json(json.dumps(data))
|
|
46
|
+
else:
|
|
47
|
+
print_resource_list(data, RESOURCE_TYPE, fmt)
|
|
48
|
+
except Exception as e:
|
|
49
|
+
handle_error(e)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@usage_app.command("submit")
|
|
53
|
+
def submit_usage(
|
|
54
|
+
file: Annotated[
|
|
55
|
+
Path, typer.Option("--file", "-f", help="JSON or YAML file with OTLP/JSON traces (use - for stdin).")
|
|
56
|
+
] = ...,
|
|
57
|
+
) -> None:
|
|
58
|
+
"""Submit OpenTelemetry traces in OTLP/JSON format."""
|
|
59
|
+
from entropy_data.cli import get_client, handle_error
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
body = read_body(file)
|
|
63
|
+
client = get_client()
|
|
64
|
+
client.post_resource(RESOURCE_PATH, body)
|
|
65
|
+
print_success("Usage traces submitted.")
|
|
66
|
+
except Exception as e:
|
|
67
|
+
handle_error(e)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@usage_app.command("delete")
|
|
71
|
+
def delete_usage(
|
|
72
|
+
scope_name: Annotated[Optional[str], typer.Option("--scope-name", help="Delete by scope name.")] = None,
|
|
73
|
+
data_product_id: Annotated[
|
|
74
|
+
Optional[str], typer.Option("--data-product-id", help="Delete by data product ID.")
|
|
75
|
+
] = None,
|
|
76
|
+
data_contract_id: Annotated[
|
|
77
|
+
Optional[str], typer.Option("--data-contract-id", help="Delete by data contract ID.")
|
|
78
|
+
] = None,
|
|
79
|
+
span_id: Annotated[Optional[str], typer.Option("--span-id", help="Delete a specific trace by span ID.")] = None,
|
|
80
|
+
) -> None:
|
|
81
|
+
"""Delete usage traces."""
|
|
82
|
+
from entropy_data.cli import get_client, handle_error
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
params = {}
|
|
86
|
+
if scope_name:
|
|
87
|
+
params["scopeName"] = scope_name
|
|
88
|
+
if data_product_id:
|
|
89
|
+
params["dataProductId"] = data_product_id
|
|
90
|
+
if data_contract_id:
|
|
91
|
+
params["dataContractId"] = data_contract_id
|
|
92
|
+
if span_id:
|
|
93
|
+
params["spanId"] = span_id
|
|
94
|
+
client = get_client()
|
|
95
|
+
result = client.delete_resources(RESOURCE_PATH, params=params or None)
|
|
96
|
+
deleted = result.get("deletedCount", "unknown")
|
|
97
|
+
print_success(f"Usage traces deleted ({deleted} deleted).")
|
|
98
|
+
except Exception as e:
|
|
99
|
+
handle_error(e)
|