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.
@@ -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)