adalab-cli 3.1.0__tar.gz → 3.2.0__tar.gz
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.
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/PKG-INFO +2 -1
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/adalab_cli/cli/app.py +9 -1
- adalab_cli-3.2.0/adalab_cli/cli/completion_tree.py +143 -0
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/adalab_cli/cli/databases_commands.py +1 -1
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/adalab_cli/cli/gallery_commands.py +60 -8
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/adalab_cli/cli/logs_commands.py +1 -1
- adalab_cli-3.2.0/adalab_cli/cli/pictures_commands.py +85 -0
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/adalab_cli/cli/schedule_commands.py +91 -2
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/adalab_cli/cli/user_commands.py +1 -1
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/pyproject.toml +18 -22
- adalab_cli-3.1.0/adalab_cli/cli/completion_tree.py +0 -83
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/README.md +0 -0
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/adalab_cli/__init__.py +0 -0
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/adalab_cli/cli/__init__.py +0 -0
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/adalab_cli/cli/authentication_flows.py +0 -0
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/adalab_cli/cli/factory.py +0 -0
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/adalab_cli/cli/interactive.py +0 -0
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/adalab_cli/cli/kernel_commands.py +0 -0
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/adalab_cli/cli/logger.py +0 -0
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/adalab_cli/cli/login_commands.py +0 -0
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/adalab_cli/cli/oci_commands.py +0 -0
- {adalab_cli-3.1.0 → adalab_cli-3.2.0}/adalab_cli/cli/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: adalab-cli
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: The CLI app to interact with AdaLab.
|
|
5
5
|
Home-page: https://adamatics.com
|
|
6
6
|
Author: Adamatics ApS
|
|
@@ -18,6 +18,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
18
18
|
Classifier: Typing :: Typed
|
|
19
19
|
Requires-Dist: adalib (>=7.2.0)
|
|
20
20
|
Requires-Dist: adalib-auth (>=1.2.2)
|
|
21
|
+
Requires-Dist: ascii-magic (>=2.3.0)
|
|
21
22
|
Requires-Dist: loguru (>=0.7.2)
|
|
22
23
|
Requires-Dist: prompt-toolkit (>=3.0.47)
|
|
23
24
|
Requires-Dist: sh (>=2.0.6)
|
|
@@ -29,13 +29,14 @@ from .interactive import interactive_mode
|
|
|
29
29
|
from .logger import Logger
|
|
30
30
|
from .login_commands import load_config
|
|
31
31
|
from .logs_commands import logs_app
|
|
32
|
+
from .pictures_commands import pictures_app
|
|
32
33
|
from .schedule_commands import schedules_app
|
|
33
34
|
from .user_commands import user_app
|
|
34
35
|
|
|
35
36
|
app = typer.Typer(no_args_is_help=False)
|
|
36
37
|
|
|
37
38
|
|
|
38
|
-
@app.callback(
|
|
39
|
+
@app.callback(invoke_without_command=True, no_args_is_help=True)
|
|
39
40
|
def main(
|
|
40
41
|
token: str = typer.Option(None, help="User token for authentication"),
|
|
41
42
|
adalab_url: str = typer.Option(None, help="URL of the AdaLab server"),
|
|
@@ -197,3 +198,10 @@ app.add_typer(
|
|
|
197
198
|
help="Commands for fetching AdaLab logs.",
|
|
198
199
|
no_args_is_help=True,
|
|
199
200
|
)
|
|
201
|
+
|
|
202
|
+
app.add_typer(
|
|
203
|
+
pictures_app,
|
|
204
|
+
name="pictures",
|
|
205
|
+
help="Commands for handling pictures in AdaLab.",
|
|
206
|
+
no_args_is_help=True,
|
|
207
|
+
)
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""Map of the CLI commands and subcommands for the CLI completion tree."""
|
|
2
|
+
|
|
3
|
+
completion_tree = {
|
|
4
|
+
"cards": {
|
|
5
|
+
"toggle-review": {"help": None, "exit": None},
|
|
6
|
+
"expose-card": {"help": None, "exit": None},
|
|
7
|
+
"get-card": {"help": None, "--incl-content": None, "exit": None},
|
|
8
|
+
"hide-card": {"help": None, "exit": None},
|
|
9
|
+
"list-cards": {
|
|
10
|
+
"all": {
|
|
11
|
+
"--search-phrase": None,
|
|
12
|
+
"--group-category": None,
|
|
13
|
+
"--only-hidden": None,
|
|
14
|
+
"--only-exposed": None,
|
|
15
|
+
"help": None,
|
|
16
|
+
"exit": None,
|
|
17
|
+
},
|
|
18
|
+
"notebook": {
|
|
19
|
+
"--search-phrase": None,
|
|
20
|
+
"--group-category": None,
|
|
21
|
+
"--only-hidden": None,
|
|
22
|
+
"--only-exposed": None,
|
|
23
|
+
"help": None,
|
|
24
|
+
"exit": None,
|
|
25
|
+
},
|
|
26
|
+
"voila": {
|
|
27
|
+
"--search-phrase": None,
|
|
28
|
+
"--group-category": None,
|
|
29
|
+
"--only-hidden": None,
|
|
30
|
+
"--only-exposed": None,
|
|
31
|
+
"help": None,
|
|
32
|
+
"exit": None,
|
|
33
|
+
},
|
|
34
|
+
"url": {
|
|
35
|
+
"--search-phrase": None,
|
|
36
|
+
"--group-category": None,
|
|
37
|
+
"--url-subtype": None,
|
|
38
|
+
"--only-hidden": None,
|
|
39
|
+
"--only-exposed": None,
|
|
40
|
+
"help": None,
|
|
41
|
+
"exit": None,
|
|
42
|
+
},
|
|
43
|
+
"group": {
|
|
44
|
+
"--search-phrase": None,
|
|
45
|
+
"--group-category": None,
|
|
46
|
+
"--only-hidden": None,
|
|
47
|
+
"--only-exposed": None,
|
|
48
|
+
"help": None,
|
|
49
|
+
"exit": None,
|
|
50
|
+
},
|
|
51
|
+
"help": None,
|
|
52
|
+
"exit": None,
|
|
53
|
+
},
|
|
54
|
+
"help": None,
|
|
55
|
+
"exit": None,
|
|
56
|
+
},
|
|
57
|
+
"databases": {
|
|
58
|
+
"list-databases": {"--no-pretty": None, "help": None},
|
|
59
|
+
"list-datasets": {"--no-pretty": None, "--return-sql": None, "help": None},
|
|
60
|
+
"list-tables": {"--no-pretty": None, "help": None},
|
|
61
|
+
"view-dataset": {"--head": None, "--no-pretty": None, "help": None},
|
|
62
|
+
"help": None,
|
|
63
|
+
"exit": None,
|
|
64
|
+
},
|
|
65
|
+
"logs": {
|
|
66
|
+
"app": {
|
|
67
|
+
"--container": None,
|
|
68
|
+
"--container-index": None,
|
|
69
|
+
"--from": None,
|
|
70
|
+
"--source": None,
|
|
71
|
+
"--to": None,
|
|
72
|
+
"help": None,
|
|
73
|
+
"exit": None,
|
|
74
|
+
},
|
|
75
|
+
"build": {"--source": None, "help": None},
|
|
76
|
+
"lab": {"--from": None, "--source": None, "--to": None, "help": None},
|
|
77
|
+
"publish": {"--source": None, "help": None},
|
|
78
|
+
"run": {"help": None},
|
|
79
|
+
"help": None,
|
|
80
|
+
"exit": None,
|
|
81
|
+
},
|
|
82
|
+
"schedules": {
|
|
83
|
+
"list-schedules": {
|
|
84
|
+
"--only-active": None,
|
|
85
|
+
"--search-phrase": None,
|
|
86
|
+
"help": None,
|
|
87
|
+
"exit": None,
|
|
88
|
+
},
|
|
89
|
+
"get-schedule": {"--incl-content": None, "help": None},
|
|
90
|
+
"create-schedule": {
|
|
91
|
+
"--schedule": None,
|
|
92
|
+
"--pool": None,
|
|
93
|
+
"--active": None,
|
|
94
|
+
"--concurrent": None,
|
|
95
|
+
"--cleanup": None,
|
|
96
|
+
"--timeout": None,
|
|
97
|
+
"help": None,
|
|
98
|
+
"exit": None,
|
|
99
|
+
},
|
|
100
|
+
"delete-run": {"help": None, "exit": None},
|
|
101
|
+
"delete-schedule": {"help": None, "exit": None},
|
|
102
|
+
"start-run": {
|
|
103
|
+
"--cleanup": None,
|
|
104
|
+
"--pool": None,
|
|
105
|
+
"--timeout": None,
|
|
106
|
+
"help": None,
|
|
107
|
+
"exit": None,
|
|
108
|
+
},
|
|
109
|
+
"stop-run": {"help": None, "exit": None},
|
|
110
|
+
"update-schedule": {
|
|
111
|
+
"--schedule": None,
|
|
112
|
+
"--pool": None,
|
|
113
|
+
"--active": None,
|
|
114
|
+
"--concurrent": None,
|
|
115
|
+
"--cleanup": None,
|
|
116
|
+
"--timeout": None,
|
|
117
|
+
"help": None,
|
|
118
|
+
"exit": None,
|
|
119
|
+
},
|
|
120
|
+
"help": None,
|
|
121
|
+
"exit": None,
|
|
122
|
+
},
|
|
123
|
+
"user": {
|
|
124
|
+
"whoami": {
|
|
125
|
+
"--full-information": None,
|
|
126
|
+
"--with-notifications": None,
|
|
127
|
+
"help": None,
|
|
128
|
+
"exit": None,
|
|
129
|
+
},
|
|
130
|
+
"help": None,
|
|
131
|
+
"exit": None,
|
|
132
|
+
},
|
|
133
|
+
"pictures": {
|
|
134
|
+
"show": {"help": None, "exit": None},
|
|
135
|
+
"download": {"--output-path": None, "help": None, "exit": None},
|
|
136
|
+
"create": {"--path": None, "--url": None, "help": None, "exit": None},
|
|
137
|
+
"help": None,
|
|
138
|
+
"exit": None,
|
|
139
|
+
},
|
|
140
|
+
"version": None,
|
|
141
|
+
"help": None,
|
|
142
|
+
"exit": None,
|
|
143
|
+
}
|
|
@@ -204,7 +204,7 @@ def list_tables(
|
|
|
204
204
|
utils.print_dataframe(dataframe=tables, pretty=pretty, title=f"Tables in database {db_index}")
|
|
205
205
|
|
|
206
206
|
|
|
207
|
-
@db_app.callback(
|
|
207
|
+
@db_app.callback(invoke_without_command=True)
|
|
208
208
|
def main(
|
|
209
209
|
interactive: bool = typer.Option(
|
|
210
210
|
False, "-i", "--interactive", help="Activate interactive mode"
|
|
@@ -38,26 +38,65 @@ def gallery_list_cards(
|
|
|
38
38
|
typer.Argument(
|
|
39
39
|
help="The type of cards to list. " "Choose from [all, notebook, voila, url, group].",
|
|
40
40
|
),
|
|
41
|
-
]
|
|
41
|
+
] = "all",
|
|
42
|
+
head: Annotated[int | None, typer.Option(help="Number of cards to display.")] = None,
|
|
43
|
+
url_subtype: Annotated[
|
|
44
|
+
str,
|
|
45
|
+
typer.Option(
|
|
46
|
+
help="The URL subtype to filter by.",
|
|
47
|
+
),
|
|
48
|
+
] = "all",
|
|
49
|
+
search_phrase: Annotated[str, typer.Option(help="Search phrase to filter cards by.")] = None,
|
|
50
|
+
group_category: Annotated[str, typer.Option(help="Group category to filter by.")] = None,
|
|
51
|
+
only_hidden: Annotated[bool, typer.Option(help="Show only hidden cards.")] = False,
|
|
52
|
+
only_exposed: Annotated[bool, typer.Option(help="Show only exposed cards.")] = False,
|
|
42
53
|
):
|
|
43
54
|
"""
|
|
44
|
-
Prints all cards from the Gallery with the type CARD_TYPE.
|
|
55
|
+
Prints all cards from the Gallery with the type CARD_TYPE. Optionally filter by URL_SUBTYPE
|
|
56
|
+
for URL cards.
|
|
45
57
|
"""
|
|
46
58
|
try:
|
|
47
59
|
with Progress(
|
|
48
60
|
SpinnerColumn(), TextColumn("[progress.description]{task.description}"), transient=True
|
|
49
61
|
) as progress:
|
|
50
62
|
progress.add_task(description="Fetching data...", total=None)
|
|
51
|
-
cards = get_cards(
|
|
63
|
+
cards = get_cards(
|
|
64
|
+
card_type=card_type,
|
|
65
|
+
url_subtype=url_subtype,
|
|
66
|
+
head=head,
|
|
67
|
+
search_phrase=search_phrase,
|
|
68
|
+
group_category=group_category,
|
|
69
|
+
only_hidden=only_hidden,
|
|
70
|
+
only_exposed=only_exposed,
|
|
71
|
+
)
|
|
52
72
|
except Exception as e:
|
|
53
73
|
logger.error(f"Error: {str(e)}")
|
|
54
74
|
sys.exit()
|
|
55
75
|
|
|
56
76
|
rich_print(f"Card type: {card_type} ({len(cards)})")
|
|
57
77
|
|
|
58
|
-
|
|
78
|
+
cols = (
|
|
79
|
+
[("Card id", 0), ("Card type", 1)]
|
|
80
|
+
+ ([("URL type", 2)] if card_type == "url" else [])
|
|
81
|
+
+ [("Reviewed", 3), ("Exposed", 4), ("Card name", 5)]
|
|
82
|
+
+ ([("Cards in Group", 6)] if card_type == "group" else [])
|
|
83
|
+
+ [("Card author", 7)]
|
|
84
|
+
)
|
|
85
|
+
table = Table(
|
|
86
|
+
*[x[0] for x in cols],
|
|
87
|
+
title="Cards",
|
|
88
|
+
)
|
|
59
89
|
for card in cards:
|
|
60
|
-
table.add_row(
|
|
90
|
+
table.add_row(
|
|
91
|
+
*[
|
|
92
|
+
(
|
|
93
|
+
str(card[ind])
|
|
94
|
+
if _cname not in ["Reviewed", "Exposed"]
|
|
95
|
+
else ("✅" if card[ind] else "❌")
|
|
96
|
+
)
|
|
97
|
+
for _cname, ind in cols
|
|
98
|
+
]
|
|
99
|
+
)
|
|
61
100
|
console = Console()
|
|
62
101
|
console.print(table)
|
|
63
102
|
|
|
@@ -70,6 +109,9 @@ def gallery_get_card(
|
|
|
70
109
|
help="The ID of the card you want to retrieve.",
|
|
71
110
|
),
|
|
72
111
|
],
|
|
112
|
+
incl_content: Annotated[
|
|
113
|
+
bool, typer.Option(help="Include card content in the output.")
|
|
114
|
+
] = False,
|
|
73
115
|
):
|
|
74
116
|
"""
|
|
75
117
|
Gets the contents of a card identified by CARD_ID.
|
|
@@ -81,12 +123,22 @@ def gallery_get_card(
|
|
|
81
123
|
transient=True,
|
|
82
124
|
) as progress:
|
|
83
125
|
progress.add_task(description="Fetching data...", total=None)
|
|
84
|
-
card = get_card_contents(card_id=card_id)
|
|
126
|
+
card = get_card_contents(card_id=card_id, incl_content=incl_content)
|
|
85
127
|
except Exception:
|
|
86
128
|
rich_print(f"Card {card_id} [bold red]failed[/bold red] to retrieve.")
|
|
87
129
|
sys.exit(1)
|
|
88
130
|
|
|
89
|
-
|
|
131
|
+
console = Console()
|
|
132
|
+
|
|
133
|
+
table = Table(title="Card Details")
|
|
134
|
+
table.add_column("Property", style="cyan", no_wrap=True)
|
|
135
|
+
table.add_column("Value", style="magenta")
|
|
136
|
+
for key, value in card.items():
|
|
137
|
+
if isinstance(value, bool):
|
|
138
|
+
value = "✅" if value else "❌"
|
|
139
|
+
table.add_row(key, str(value) if value != [] else "[dim]Empty List[/dim]")
|
|
140
|
+
|
|
141
|
+
console.print(table)
|
|
90
142
|
|
|
91
143
|
|
|
92
144
|
@gallery_app.command("expose-card", no_args_is_help=True)
|
|
@@ -149,7 +201,7 @@ def gallery_toggle_card_review(
|
|
|
149
201
|
rich_print(f"Card {card_id} review status [bold green]updated[/bold green] successfully.")
|
|
150
202
|
|
|
151
203
|
|
|
152
|
-
@gallery_app.callback(
|
|
204
|
+
@gallery_app.callback(invoke_without_command=True)
|
|
153
205
|
def main(
|
|
154
206
|
interactive: bool = typer.Option(
|
|
155
207
|
False, "-i", "--interactive", help="Activate interactive mode"
|
|
@@ -320,7 +320,7 @@ def logs_get_run_logs(
|
|
|
320
320
|
console.print(table)
|
|
321
321
|
|
|
322
322
|
|
|
323
|
-
@logs_app.callback(
|
|
323
|
+
@logs_app.callback(invoke_without_command=True)
|
|
324
324
|
def main(
|
|
325
325
|
interactive: bool = typer.Option(
|
|
326
326
|
False, "-i", "--interactive", help="Activate interactive mode"
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""Pictures-related commands"""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from io import BytesIO
|
|
5
|
+
from typing import Annotated
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from adalib.adaboard import request_adaboard
|
|
9
|
+
from adalib.pictures import get_picture, post_picture, post_picture_url
|
|
10
|
+
from ascii_magic import AsciiArt
|
|
11
|
+
from prompt_toolkit.completion import NestedCompleter
|
|
12
|
+
from rich import print as rich_print
|
|
13
|
+
|
|
14
|
+
from .completion_tree import completion_tree
|
|
15
|
+
from .factory import check_authentication
|
|
16
|
+
from .interactive import interactive_mode
|
|
17
|
+
|
|
18
|
+
pictures_app = typer.Typer()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@pictures_app.command("show", no_args_is_help=True)
|
|
22
|
+
def show_picture(picture_id: Annotated[int, typer.Argument(help="The ID of the picture to show")]):
|
|
23
|
+
"""Show the specific picture as an ASCII art"""
|
|
24
|
+
try:
|
|
25
|
+
data = BytesIO(request_adaboard(f"image/{picture_id}").content)
|
|
26
|
+
AsciiArt.from_image(data).to_terminal()
|
|
27
|
+
except Exception:
|
|
28
|
+
rich_print(f"Could not show the picture with ID: {picture_id}")
|
|
29
|
+
sys.exit(1)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@pictures_app.command("download", no_args_is_help=True)
|
|
33
|
+
def download_picture(
|
|
34
|
+
picture_id: Annotated[int, typer.Argument(help="The ID of the picture to download")],
|
|
35
|
+
output_path: Annotated[
|
|
36
|
+
str | None, typer.Option(help="The path to save the picture to")
|
|
37
|
+
] = None,
|
|
38
|
+
):
|
|
39
|
+
"""Download the specific picture into a file."""
|
|
40
|
+
if output_path is None:
|
|
41
|
+
output_path = f"picture_{picture_id}"
|
|
42
|
+
try:
|
|
43
|
+
get_picture(picture_id=picture_id, output_file_path=output_path)
|
|
44
|
+
except Exception:
|
|
45
|
+
rich_print(f"Could not download the picture with ID: {picture_id}")
|
|
46
|
+
sys.exit(1)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@pictures_app.command("create", no_args_is_help=True)
|
|
50
|
+
def create_new_picture(
|
|
51
|
+
path: Annotated[str | None, typer.Option(help="The path to the picture file")] = None,
|
|
52
|
+
url: Annotated[str | None, typer.Option(help="The URL of the picture")] = None,
|
|
53
|
+
):
|
|
54
|
+
"""Create a new picture from a file or URL."""
|
|
55
|
+
if (path is not None and url is not None) or (path is None and url is None):
|
|
56
|
+
rich_print("Please provide either a path or a URL to create a picture.")
|
|
57
|
+
sys.exit(1)
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
if path is not None:
|
|
61
|
+
picture_id = post_picture(input_file_path=path)
|
|
62
|
+
else:
|
|
63
|
+
picture_id = post_picture_url(picture_url=url)
|
|
64
|
+
|
|
65
|
+
rich_print(f"Picture created with ID: {picture_id}")
|
|
66
|
+
except Exception:
|
|
67
|
+
rich_print("Could not create the picture.")
|
|
68
|
+
sys.exit(1)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@pictures_app.callback(invoke_without_command=True)
|
|
72
|
+
def main(
|
|
73
|
+
interactive: bool = typer.Option(
|
|
74
|
+
False, "-i", "--interactive", help="Activate interactive mode"
|
|
75
|
+
)
|
|
76
|
+
):
|
|
77
|
+
if interactive:
|
|
78
|
+
interactive_mode(
|
|
79
|
+
this_app=pictures_app,
|
|
80
|
+
title="pictures",
|
|
81
|
+
color="maroon",
|
|
82
|
+
completion=NestedCompleter.from_nested_dict(completion_tree["pictures"]),
|
|
83
|
+
)
|
|
84
|
+
else:
|
|
85
|
+
check_authentication()
|
|
@@ -10,10 +10,11 @@ Functions:
|
|
|
10
10
|
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
|
+
import base64
|
|
13
14
|
import sys
|
|
14
15
|
|
|
15
16
|
import typer
|
|
16
|
-
from adalib.adaboard import get_user
|
|
17
|
+
from adalib.adaboard import get_all_pages, get_user, request_adaboard
|
|
17
18
|
from adalib.schedules import (
|
|
18
19
|
create_schedule,
|
|
19
20
|
delete_run,
|
|
@@ -24,6 +25,7 @@ from adalib.schedules import (
|
|
|
24
25
|
)
|
|
25
26
|
from prompt_toolkit.completion import NestedCompleter
|
|
26
27
|
from rich import print as rich_print
|
|
28
|
+
from rich.table import Table
|
|
27
29
|
from typing_extensions import Annotated
|
|
28
30
|
|
|
29
31
|
from .completion_tree import completion_tree
|
|
@@ -33,6 +35,93 @@ from .interactive import interactive_mode
|
|
|
33
35
|
schedules_app = typer.Typer()
|
|
34
36
|
|
|
35
37
|
|
|
38
|
+
@schedules_app.command("list-schedules", no_args_is_help=False)
|
|
39
|
+
def list_all_schedules(
|
|
40
|
+
only_active: Annotated[bool, typer.Option(help="Include only active schedules")] = False,
|
|
41
|
+
search_phrase: Annotated[str, typer.Option(help="Search phrase to filter schedules")] = None,
|
|
42
|
+
):
|
|
43
|
+
"""Lists all available schedules."""
|
|
44
|
+
params = dict()
|
|
45
|
+
if only_active:
|
|
46
|
+
params = {"only_active": True}
|
|
47
|
+
|
|
48
|
+
if search_phrase is not None:
|
|
49
|
+
params["search"] = search_phrase
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
res = get_all_pages("schedules/v2", params=params)
|
|
53
|
+
except Exception:
|
|
54
|
+
rich_print("Failed to list schedules.")
|
|
55
|
+
sys.exit(1)
|
|
56
|
+
|
|
57
|
+
cols = ["ID", "Name", "Owner", "Cron", "Pool", "Active", "Last Run", "Next Run"]
|
|
58
|
+
table = Table(
|
|
59
|
+
*[x for x in cols],
|
|
60
|
+
title="Schedules",
|
|
61
|
+
)
|
|
62
|
+
for row in res:
|
|
63
|
+
table.add_row(
|
|
64
|
+
str(row["schedule_id"]),
|
|
65
|
+
row["name"],
|
|
66
|
+
row["owner"]["name"],
|
|
67
|
+
row["cron"],
|
|
68
|
+
row["pool"],
|
|
69
|
+
"✅" if row["active"] else "❌",
|
|
70
|
+
row["last_scheduled_ts"] or "N/A",
|
|
71
|
+
row["next_scheduled_ts"] or "N/A",
|
|
72
|
+
)
|
|
73
|
+
rich_print(table)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@schedules_app.command("get-schedule", no_args_is_help=True)
|
|
77
|
+
def get_single_schedule(
|
|
78
|
+
schedule_id: Annotated[int, typer.Argument(help="ID of the schedule.")],
|
|
79
|
+
incl_content: Annotated[bool, typer.Option(help="Include the schedule content.")] = False,
|
|
80
|
+
):
|
|
81
|
+
"""Retrieves the details of a single schedule."""
|
|
82
|
+
params = {"with_content": incl_content}
|
|
83
|
+
try:
|
|
84
|
+
res = request_adaboard(f"schedules/v2/{schedule_id}", params=params).json()
|
|
85
|
+
except Exception:
|
|
86
|
+
rich_print(f"Failed to get schedule {schedule_id}.")
|
|
87
|
+
sys.exit(1)
|
|
88
|
+
|
|
89
|
+
if res["content"]:
|
|
90
|
+
for _content in res["content"]:
|
|
91
|
+
_content["content"] = base64.b64decode(_content["content"]).decode("utf-8")
|
|
92
|
+
|
|
93
|
+
schedule = {
|
|
94
|
+
"ID": schedule_id,
|
|
95
|
+
"Name": res["name"],
|
|
96
|
+
"Owner": res["owner"]["name"],
|
|
97
|
+
"Runner": res["runner"]["name"],
|
|
98
|
+
"Timeout": res["timeout"],
|
|
99
|
+
"Pool": res["pool"],
|
|
100
|
+
"Active": "✅" if res["active"] else "❌",
|
|
101
|
+
"Timezone": res["timezone"],
|
|
102
|
+
"Cron": res["cron"],
|
|
103
|
+
"Last Run": res["last_scheduled_ts"] or "N/A",
|
|
104
|
+
"Next Run": res["next_scheduled_ts"] or "N/A",
|
|
105
|
+
"Concurrent": "✅" if res["concurrent"] else "❌",
|
|
106
|
+
"Cleanup": "✅" if res["cleanup"] else "❌",
|
|
107
|
+
"Contents": res["content"],
|
|
108
|
+
"Inputs": res["run_config"]["inputs"],
|
|
109
|
+
"Pre-run script": res["run_config"]["scripts"]["pre_run_script"] or "N/A",
|
|
110
|
+
"Post-run script": res["run_config"]["scripts"]["post_run_script"] or "N/A",
|
|
111
|
+
"Kernel ID": res["kernel_metadata_id"],
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
table = Table(title="Schedule Details")
|
|
115
|
+
table.add_column("Property", style="cyan", no_wrap=True)
|
|
116
|
+
table.add_column("Value", style="magenta")
|
|
117
|
+
for key, value in schedule.items():
|
|
118
|
+
if isinstance(value, bool):
|
|
119
|
+
value = "✅" if value else "❌"
|
|
120
|
+
table.add_row(key, str(value) if value != [] else "[dim]Empty List[/dim]")
|
|
121
|
+
|
|
122
|
+
rich_print(table)
|
|
123
|
+
|
|
124
|
+
|
|
36
125
|
@schedules_app.command("start-run", no_args_is_help=True)
|
|
37
126
|
def notebooks_start_run(
|
|
38
127
|
schedule_id: Annotated[int, typer.Argument(help="ID of the schedule to start run.")]
|
|
@@ -172,7 +261,7 @@ def notebooks_delete_schedule(
|
|
|
172
261
|
sys.exit(1)
|
|
173
262
|
|
|
174
263
|
|
|
175
|
-
@schedules_app.callback(
|
|
264
|
+
@schedules_app.callback(invoke_without_command=True)
|
|
176
265
|
def main(
|
|
177
266
|
interactive: bool = typer.Option(
|
|
178
267
|
False, "-i", "--interactive", help="Activate interactive mode"
|
|
@@ -58,7 +58,7 @@ def user_who_am_i_in_adalab(
|
|
|
58
58
|
console.print(table)
|
|
59
59
|
|
|
60
60
|
|
|
61
|
-
@user_app.callback(
|
|
61
|
+
@user_app.callback(invoke_without_command=True)
|
|
62
62
|
def main(
|
|
63
63
|
interactive: bool = typer.Option(
|
|
64
64
|
False, "-i", "--interactive", help="Activate interactive mode"
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "adalab-cli"
|
|
3
|
-
version = "3.
|
|
3
|
+
version = "3.2.0"
|
|
4
4
|
description = "The CLI app to interact with AdaLab."
|
|
5
|
-
keywords = [
|
|
5
|
+
keywords = ["cli"]
|
|
6
6
|
|
|
7
7
|
[[project.authors]]
|
|
8
8
|
name = "Adamatics ApS"
|
|
@@ -10,35 +10,34 @@ email = "info@adamatics.com"
|
|
|
10
10
|
|
|
11
11
|
[tool.poetry]
|
|
12
12
|
name = "adalab-cli"
|
|
13
|
-
version = "3.
|
|
13
|
+
version = "3.2.0"
|
|
14
14
|
description = "The CLI app to interact with AdaLab."
|
|
15
15
|
authors = ["Adamatics ApS <info@adamatics.com>"]
|
|
16
16
|
readme = "README.md"
|
|
17
17
|
homepage = "https://adamatics.com"
|
|
18
18
|
repository = "https://gitlab.com/adamatics/python/adalab-cli"
|
|
19
19
|
classifiers = [
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
]
|
|
29
|
-
packages = [
|
|
30
|
-
{ include = "adalab_cli" }
|
|
20
|
+
"Development Status :: 4 - Beta",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
"Programming Language :: Python",
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Programming Language :: Python :: 3.10",
|
|
26
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
27
|
+
"Typing :: Typed",
|
|
31
28
|
]
|
|
29
|
+
packages = [{ include = "adalab_cli" }]
|
|
32
30
|
|
|
33
31
|
[tool.poetry.dependencies]
|
|
34
32
|
python = "^3.10.0"
|
|
35
33
|
tabulate = ">=0.9.0"
|
|
36
34
|
typer = ">=0.9.0"
|
|
37
35
|
sh = ">=2.0.6"
|
|
38
|
-
adalib = {version = ">=7.2.0", source = "adalib-dev"}
|
|
39
|
-
adalib-auth = {version = ">=1.2.2", source = "adalib-dev"}
|
|
36
|
+
adalib = { version = ">=7.2.0", source = "adalib-dev" }
|
|
37
|
+
adalib-auth = { version = ">=1.2.2", source = "adalib-dev" }
|
|
40
38
|
loguru = ">=0.7.2"
|
|
41
39
|
prompt-toolkit = ">=3.0.47"
|
|
40
|
+
ascii-magic = ">=2.3.0"
|
|
42
41
|
|
|
43
42
|
[tool.poetry.group.dev.dependencies]
|
|
44
43
|
black = "^23.9.1"
|
|
@@ -87,8 +86,8 @@ line-length = 99
|
|
|
87
86
|
[tool.flake8]
|
|
88
87
|
ignore = ["E203", "E266", "E501", "W503"]
|
|
89
88
|
max-complexity = 18
|
|
90
|
-
select = ["B","C","E","F","W","T4"]
|
|
91
|
-
exclude = [".git",".venv",".tox"]
|
|
89
|
+
select = ["B", "C", "E", "F", "W", "T4"]
|
|
90
|
+
exclude = [".git", ".venv", ".tox"]
|
|
92
91
|
max-line-length = 99
|
|
93
92
|
|
|
94
93
|
[tool.pytest]
|
|
@@ -104,10 +103,7 @@ addopts = """\
|
|
|
104
103
|
|
|
105
104
|
[tool.coverage.report]
|
|
106
105
|
fail_under = 100
|
|
107
|
-
exclude_lines = [
|
|
108
|
-
'if TYPE_CHECKING:',
|
|
109
|
-
'pragma: no cover'
|
|
110
|
-
]
|
|
106
|
+
exclude_lines = ['if TYPE_CHECKING:', 'pragma: no cover']
|
|
111
107
|
|
|
112
108
|
[tool.mypy]
|
|
113
109
|
disallow_any_unimported = true
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
"""Map of the CLI commands and subcommands for the CLI completion tree."""
|
|
2
|
-
|
|
3
|
-
completion_tree = {
|
|
4
|
-
"cards": {
|
|
5
|
-
"approve-card": {"--help": None},
|
|
6
|
-
"expose-card": {"--help": None},
|
|
7
|
-
"get-card": {"--help": None},
|
|
8
|
-
"hide-card": {"--help": None},
|
|
9
|
-
"list-cards": {
|
|
10
|
-
"all": None,
|
|
11
|
-
"notebook": None,
|
|
12
|
-
"voila": None,
|
|
13
|
-
"url": None,
|
|
14
|
-
"group": None,
|
|
15
|
-
"--help": None,
|
|
16
|
-
},
|
|
17
|
-
"help": None,
|
|
18
|
-
"exit": None,
|
|
19
|
-
},
|
|
20
|
-
"databases": {
|
|
21
|
-
"list-databases": {"--no-pretty": None, "--help": None},
|
|
22
|
-
"list-datasets": {"--no-pretty": None, "--return-sql": None, "--help": None},
|
|
23
|
-
"list-tables": {"--no-pretty": None, "--help": None},
|
|
24
|
-
"view-dataset": {"--head": None, "--no-pretty": None, "--help": None},
|
|
25
|
-
"help": None,
|
|
26
|
-
"exit": None,
|
|
27
|
-
},
|
|
28
|
-
"logs": {
|
|
29
|
-
"app": {
|
|
30
|
-
"--container": None,
|
|
31
|
-
"--container-index": None,
|
|
32
|
-
"--from": None,
|
|
33
|
-
"--source": None,
|
|
34
|
-
"--to": None,
|
|
35
|
-
"--help": None,
|
|
36
|
-
},
|
|
37
|
-
"build": {"--source": None, "--help": None},
|
|
38
|
-
"lab": {"--from": None, "--source": None, "--to": None, "--help": None},
|
|
39
|
-
"publish": {"--source": None, "--help": None},
|
|
40
|
-
"run": {"--help": None},
|
|
41
|
-
"help": None,
|
|
42
|
-
"exit": None,
|
|
43
|
-
},
|
|
44
|
-
"schedules": {
|
|
45
|
-
"create-schedule": {
|
|
46
|
-
"--schedule": None,
|
|
47
|
-
"--pool": None,
|
|
48
|
-
"--active": None,
|
|
49
|
-
"--concurrent": None,
|
|
50
|
-
"--cleanup": None,
|
|
51
|
-
"--timeout": None,
|
|
52
|
-
"--help": None,
|
|
53
|
-
},
|
|
54
|
-
"delete-run": {"--help": None},
|
|
55
|
-
"delete-schedule": {"--help": None},
|
|
56
|
-
"start-run": {
|
|
57
|
-
"--cleanup": None,
|
|
58
|
-
"--pool": None,
|
|
59
|
-
"--timeout": None,
|
|
60
|
-
"--help": None,
|
|
61
|
-
},
|
|
62
|
-
"stop-run": {"--help": None},
|
|
63
|
-
"update-schedule": {
|
|
64
|
-
"--schedule": None,
|
|
65
|
-
"--pool": None,
|
|
66
|
-
"--active": None,
|
|
67
|
-
"--concurrent": None,
|
|
68
|
-
"--cleanup": None,
|
|
69
|
-
"--timeout": None,
|
|
70
|
-
"--help": None,
|
|
71
|
-
},
|
|
72
|
-
"help": None,
|
|
73
|
-
"exit": None,
|
|
74
|
-
},
|
|
75
|
-
"user": {
|
|
76
|
-
"whoami": {"--full-information": None, "--with-notifications": None, "--help": None},
|
|
77
|
-
"help": None,
|
|
78
|
-
"exit": None,
|
|
79
|
-
},
|
|
80
|
-
"version": None,
|
|
81
|
-
"help": None,
|
|
82
|
-
"exit": None,
|
|
83
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|