tabsdata-cli 2.0.0__cp312-abi3-win_amd64.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.
Files changed (39) hide show
  1. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/__init__.py +5 -0
  2. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/_registry.py +78 -0
  3. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/assets/manifest/BANNER +5 -0
  4. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/assets/manifest/LICENSE +3 -0
  5. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/assets/manifest/README-PyPi.md +8 -0
  6. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/assets/manifest/RELEASE-NOTES +1 -0
  7. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/assets/manifest/THIRD-PARTY +3 -0
  8. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/assets/manifest/VERSION +1 -0
  9. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/cli_utils.py +993 -0
  10. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/shell.py +390 -0
  11. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/__init__.py +3 -0
  12. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/auth_group.py +197 -0
  13. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/cli.py +508 -0
  14. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/collection_group.py +458 -0
  15. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/config_utils.py +93 -0
  16. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/connection_group.py +159 -0
  17. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/examples_group.py +206 -0
  18. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/execution_utils.py +429 -0
  19. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/fn_group.py +1109 -0
  20. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/fnrun_group.py +285 -0
  21. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/group_group.py +184 -0
  22. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/metrics_group.py +323 -0
  23. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/permission_group.py +259 -0
  24. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/plan_group.py +324 -0
  25. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/project_group.py +170 -0
  26. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/role_group.py +630 -0
  27. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/settings_group.py +344 -0
  28. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/table_group.py +600 -0
  29. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/trigger_group.py +338 -0
  30. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/trx_group.py +329 -0
  31. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/user_group.py +200 -0
  32. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/td/worker_group.py +185 -0
  33. tabsdata_cli-2.0.0.data/purelib/tabsdatak/cli/template.py +781 -0
  34. tabsdata_cli-2.0.0.data/purelib/tabsdatak/py.typed +0 -0
  35. tabsdata_cli-2.0.0.dist-info/METADATA +39 -0
  36. tabsdata_cli-2.0.0.dist-info/RECORD +39 -0
  37. tabsdata_cli-2.0.0.dist-info/WHEEL +5 -0
  38. tabsdata_cli-2.0.0.dist-info/licenses/src/main/python/tabsdatak/cli/assets/manifest/LICENSE +3 -0
  39. tabsdata_cli-2.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,200 @@
1
+ #
2
+ # Copyright 2026 Tabsdata Inc.
3
+ #
4
+
5
+
6
+ import rich_click as click
7
+ from rich.table import Table
8
+
9
+ from tabsdatak.cli._registry import cli_command
10
+ from tabsdatak.cli.cli_utils import (
11
+ echo_more_results,
12
+ format_option,
13
+ hint_common_solutions,
14
+ logical_prompt,
15
+ make_console,
16
+ max_result_option,
17
+ render,
18
+ take,
19
+ verify_login_or_prompt,
20
+ )
21
+
22
+
23
+ @cli_command
24
+ @click.group()
25
+ def user():
26
+ """User management commands"""
27
+
28
+
29
+ @user.command()
30
+ @click.option("--name", "-n", help="Name of the user to create.")
31
+ @click.option("--full-name", "-f", help="Full name of the user.")
32
+ @click.option("--email", "-e", help="Email of the user.")
33
+ @click.option(
34
+ "--password",
35
+ "-p",
36
+ help="Password for the user. Will be prompted for it if not provided.",
37
+ )
38
+ @click.option("--disabled", is_flag=True, default=False, help="Disable the user.")
39
+ @click.pass_context
40
+ def create(
41
+ ctx: click.Context,
42
+ name: str,
43
+ full_name: str,
44
+ email: str,
45
+ password: str,
46
+ disabled: bool,
47
+ ):
48
+ """Create a new user"""
49
+ verify_login_or_prompt(ctx)
50
+ click.echo("Creating a new user")
51
+ click.echo("-" * 10)
52
+ name = name or logical_prompt(ctx, "Name of the user")
53
+ if password is None:
54
+ password = logical_prompt(ctx, "Password for the user", hide_input=True)
55
+ second_password = logical_prompt(
56
+ ctx, "Please re-enter the password", hide_input=True
57
+ )
58
+ if password != second_password:
59
+ raise click.ClickException("Passwords do not match.")
60
+ full_name = full_name or logical_prompt(
61
+ ctx, "Full name of the user", default_value=name
62
+ )
63
+ email = email or logical_prompt(ctx, "Email of the user", default_value="")
64
+ try:
65
+ ctx.obj["tabsdataserver"].create_user(
66
+ name,
67
+ password,
68
+ full_name=full_name,
69
+ email=email if email else None,
70
+ enabled=not disabled,
71
+ )
72
+ click.echo("User created successfully")
73
+ except Exception as e:
74
+ hint_common_solutions(ctx, e)
75
+ raise click.ClickException(f"Failed to create user: {e}")
76
+
77
+
78
+ @user.command()
79
+ @click.option("--name", "-n", help="Name of the user to delete.")
80
+ @click.option(
81
+ "--confirm",
82
+ help="Write 'delete' to confirm deletion. Will be prompted for it if not provided.",
83
+ )
84
+ @click.pass_context
85
+ def delete(ctx: click.Context, name: str, confirm: str):
86
+ """Delete a user by name"""
87
+ verify_login_or_prompt(ctx)
88
+ name = name or logical_prompt(ctx, "Name of the user to delete")
89
+ click.echo(f"Deleting user: {name}")
90
+ click.echo("-" * 10)
91
+ confirm = confirm or logical_prompt(ctx, "Please type 'delete' to confirm deletion")
92
+ if confirm != "delete":
93
+ raise click.ClickException(
94
+ "Deletion not confirmed. The confirmation word is 'delete'."
95
+ )
96
+ try:
97
+ ctx.obj["tabsdataserver"].delete_user(name)
98
+ click.echo("User deleted successfully")
99
+ except Exception as e:
100
+ hint_common_solutions(ctx, e)
101
+ raise click.ClickException(f"Failed to delete user: {e}")
102
+
103
+
104
+ @user.command()
105
+ @format_option
106
+ @click.option("--name", "-n", help="Name of the user to display.")
107
+ @click.pass_context
108
+ def get(ctx: click.Context, name: str):
109
+ """Display a user by name"""
110
+ verify_login_or_prompt(ctx)
111
+ name = name or logical_prompt(ctx, "Name of the user to display")
112
+ try:
113
+ user = ctx.obj["tabsdataserver"].get_user(name)
114
+
115
+ def _table():
116
+ table = Table(title="User")
117
+ table.add_column("Name", style="cyan", no_wrap=True)
118
+ table.add_column("Full name")
119
+ table.add_column("Email")
120
+ table.add_column("Enabled")
121
+ table.add_row(user.name, user.full_name, user.email, str(user.enabled))
122
+ click.echo()
123
+ make_console().print(table)
124
+ click.echo()
125
+
126
+ render(ctx, data=lambda: user._data, table=_table)
127
+ except Exception as e:
128
+ hint_common_solutions(ctx, e)
129
+ raise click.ClickException(f"Failed to display user: {e}")
130
+
131
+
132
+ @user.command()
133
+ @format_option
134
+ @max_result_option
135
+ @click.pass_context
136
+ def list(ctx: click.Context):
137
+ """List all users"""
138
+ verify_login_or_prompt(ctx)
139
+ try:
140
+ list_of_users, truncated = take(
141
+ ctx, ctx.obj["tabsdataserver"].list_users_generator()
142
+ )
143
+
144
+ def _table():
145
+ table = Table(title="Users")
146
+ table.add_column("Name", style="cyan", no_wrap=True)
147
+ table.add_column("Full name")
148
+ table.add_column("Email")
149
+ table.add_column("Enabled")
150
+ for user in list_of_users:
151
+ table.add_row(user.name, user.full_name, user.email, str(user.enabled))
152
+ click.echo()
153
+ make_console().print(table)
154
+ click.echo(f"Number of users: {len(list_of_users)}")
155
+ click.echo()
156
+
157
+ render(ctx, data=lambda: [u._data for u in list_of_users], table=_table)
158
+ echo_more_results(ctx, truncated)
159
+ except Exception as e:
160
+ hint_common_solutions(ctx, e)
161
+ raise click.ClickException(f"Failed to list users: {e}")
162
+
163
+
164
+ @user.command()
165
+ @click.option("--name", "-n", help="Name of the user to update.")
166
+ @click.option("--full-name", "-f", help="New full name of the user.")
167
+ @click.option("--email", "-e", help="New email of the user.")
168
+ @click.option("--password", "-p", help="New password for the user.")
169
+ @click.option(
170
+ "--enabled",
171
+ type=bool,
172
+ default=None,
173
+ help="Indicate if the user is enabled or disabled",
174
+ )
175
+ @click.pass_context
176
+ def update(
177
+ ctx: click.Context,
178
+ name: str,
179
+ full_name: str,
180
+ email: str,
181
+ password: str,
182
+ enabled: bool,
183
+ ):
184
+ """Update a user by name"""
185
+ verify_login_or_prompt(ctx)
186
+ name = name or logical_prompt(ctx, "Name of the user to update")
187
+ click.echo(f"Updating user: {name}")
188
+ click.echo("-" * 10)
189
+ try:
190
+ ctx.obj["tabsdataserver"].update_user(
191
+ name,
192
+ full_name=full_name,
193
+ email=email,
194
+ password=password,
195
+ enabled=enabled,
196
+ )
197
+ click.echo("User updated successfully")
198
+ except Exception as e:
199
+ hint_common_solutions(ctx, e)
200
+ raise click.ClickException(f"Failed to update user: {e}")
@@ -0,0 +1,185 @@
1
+ #
2
+ # Copyright 2026 Tabsdata Inc.
3
+ #
4
+
5
+ from __future__ import annotations
6
+
7
+ from typing import TYPE_CHECKING, List
8
+
9
+ import rich_click as click
10
+
11
+ from tabsdatak.cli._registry import cli_command
12
+ from tabsdatak.cli.cli_utils import (
13
+ echo_more_results,
14
+ format_option,
15
+ hint_common_solutions,
16
+ make_console,
17
+ max_result_option,
18
+ output_format,
19
+ render,
20
+ show_hint,
21
+ take,
22
+ verify_login_or_prompt,
23
+ )
24
+ from tabsdatak.cli.td.execution_utils import (
25
+ echo_function_run_status,
26
+ echo_plan_status,
27
+ echo_transaction_status,
28
+ emit_worker_logs,
29
+ obtain_list_worker_filters,
30
+ span_projects,
31
+ workers_table,
32
+ )
33
+ from tabsdatak.sdk.status_utils.worker import WORKER_VALID_USER_PROVIDED_STATUSES
34
+
35
+ if TYPE_CHECKING:
36
+ from tabsdatak.sdk.tabsdata_server import TabsdataServer
37
+
38
+
39
+ @cli_command
40
+ @click.group()
41
+ def worker():
42
+ """Worker management commands"""
43
+
44
+
45
+ @worker.command(name="list")
46
+ @click.option("--proj", type=str, help="Name of the project to filter workers by.")
47
+ @click.option(
48
+ "--status",
49
+ type=str,
50
+ multiple=True,
51
+ help=(
52
+ "Filter workers by status. The possible statuses are "
53
+ f"'{WORKER_VALID_USER_PROVIDED_STATUSES}'. This field is "
54
+ "case-insensitive. "
55
+ ),
56
+ )
57
+ @click.option(
58
+ "--coll",
59
+ type=str,
60
+ help="Collection of the function to which the workers belong.",
61
+ )
62
+ @click.option(
63
+ "--fn", type=str, help="Name of the function to which the workers belong."
64
+ )
65
+ @click.option("--plan", type=str, help="ID of the plan to filter workers by.")
66
+ @click.option(
67
+ "--plan-name",
68
+ help=(
69
+ "A plan name wildcard to match. "
70
+ "For example, 'my_plan*' will match all plans "
71
+ "with names starting with 'my_plan'."
72
+ ),
73
+ )
74
+ @click.option("--fnrun", type=str, help="ID of the function run to filter workers by.")
75
+ @click.option("--trx", type=str, help="ID of the transaction to filter workers by.")
76
+ @format_option
77
+ @max_result_option
78
+ @click.pass_context
79
+ def list_workers(
80
+ ctx: click.Context,
81
+ proj: str,
82
+ status: List[str],
83
+ coll: str,
84
+ fn: str,
85
+ plan: str,
86
+ plan_name: str,
87
+ fnrun: str,
88
+ trx: str,
89
+ ):
90
+ """List workers across every project you can view."""
91
+ verify_login_or_prompt(ctx)
92
+ try:
93
+ server: TabsdataServer = ctx.obj["tabsdataserver"]
94
+ span_projects(server)
95
+ request_filter = obtain_list_worker_filters(
96
+ status=status,
97
+ exe_name=plan_name,
98
+ execution_id=plan,
99
+ fn=fn,
100
+ fnrun=fnrun,
101
+ collection=coll,
102
+ trx=trx,
103
+ project=proj,
104
+ )
105
+ if output_format(ctx) == "table":
106
+ if plan:
107
+ echo_plan_status(server, plan)
108
+ if trx:
109
+ echo_transaction_status(server, trx)
110
+ if fnrun:
111
+ echo_function_run_status(server, fnrun)
112
+ list_of_workers, truncated = take(
113
+ ctx, server.list_workers_generator(filter=request_filter)
114
+ )
115
+
116
+ if output_format(ctx) != "table":
117
+ render(
118
+ ctx,
119
+ data=[w._data for w in list_of_workers],
120
+ table=lambda: None,
121
+ )
122
+ echo_more_results(ctx, truncated)
123
+ return
124
+
125
+ click.echo()
126
+ console = make_console()
127
+ console.print(workers_table(list_of_workers))
128
+ click.echo(f"Number of workers: {len(list_of_workers)}")
129
+ echo_more_results(ctx, truncated)
130
+ click.echo()
131
+ show_hint(
132
+ ctx,
133
+ "Read logs with 'tdk worker logs --worker <WORKER-ID>', or "
134
+ "'tdk fnrun logs --fnrun <RUN-ID>' for a function run's workers.",
135
+ )
136
+ except Exception as e:
137
+ hint_common_solutions(ctx, e)
138
+ raise click.ClickException(f"Failed to list workers: {e}")
139
+
140
+
141
+ @worker.command()
142
+ @click.option("--worker", required=True, help="ID of the worker whose logs to show.")
143
+ @click.option(
144
+ "--file",
145
+ help=(
146
+ "Path of the file where the logs will be saved, or '-' to write them to "
147
+ "stdout. Any folders provided before the file must already exist."
148
+ ),
149
+ )
150
+ @format_option
151
+ @click.pass_context
152
+ def logs(ctx: click.Context, worker: str, file: str):
153
+ """
154
+ Show the logs of a worker.
155
+ """
156
+ verify_login_or_prompt(ctx)
157
+ try:
158
+ server: TabsdataServer = ctx.obj["tabsdataserver"]
159
+ emit_worker_logs(ctx, server, worker, file)
160
+ except Exception as e:
161
+ hint_common_solutions(ctx, e)
162
+ raise click.ClickException(f"Failed to show logs: {e}")
163
+
164
+
165
+ @worker.command()
166
+ @click.option("--worker", required=True, help="ID of the worker to recover.")
167
+ @click.pass_context
168
+ def recover(ctx: click.Context, worker: str):
169
+ """
170
+ Recover the transaction a worker belongs to: the transaction's failed or
171
+ on-hold function runs are re-scheduled.
172
+ """
173
+ verify_login_or_prompt(ctx)
174
+ try:
175
+ server: TabsdataServer = ctx.obj["tabsdataserver"]
176
+ span_projects(server)
177
+ target = server.get_worker(worker)
178
+ trx = target.transaction.id
179
+ click.echo(f"Recovering transaction '{trx}' of worker '{worker}'")
180
+ click.echo("-" * 10)
181
+ server.recover_transaction(trx)
182
+ click.echo("Transaction recovered successfully")
183
+ except Exception as e:
184
+ hint_common_solutions(ctx, e)
185
+ raise click.ClickException(f"Failed to recover worker: {e}")