Skip to content
This repository was archived by the owner on Sep 12, 2024. It is now read-only.

Commit ed7b0cc

Browse files
authored
Merge pull request #6 from textcortex/update-parser
Improve parser and configuration functionality
2 parents fa68a29 + 203697f commit ed7b0cc

File tree

19 files changed

+486
-172
lines changed

19 files changed

+486
-172
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,4 @@ jobs:
4343
pytest
4444
- name: Check if the main script is installed
4545
run: |
46-
icortex --help
46+
icortex help

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,6 @@ cache.json
137137
Untitled*.ipynb
138138
pyproject.toml
139139
poetry.lock
140+
tmp/
141+
lab/
142+
*.csv

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ To install the ICortex Kernel, run the following in the main project directory:
2424
pip install icortex
2525
```
2626

27-
This install the Python package and the `icortex` command line interface. You will need to run `icortex` once to install the kernel spec to Jupyter.
27+
This will install the Python package and the `icortex` command line interface. You will need to run `icortex` once to install the kernel spec to Jupyter.
2828

2929
## Using ICortex
3030

@@ -85,7 +85,7 @@ Hello World.
8585
1 1 2 3 5 8 13 21 34 55 89
8686
```
8787

88-
You can also specify options with command line flags, e.g. to auto-install packages, auto-execute the returned code and so on. To see the complete list of options for your chosen service, run:
88+
You can also specify variables or options with command line flags, e.g. to auto-install packages, auto-execute the returned code and so on. To see the complete list of variables for your chosen service, run:
8989

9090
```
9191
/help

icortex/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
from icortex.kernel import ICortexKernel, print_help
1+
from icortex.kernel import ICortexKernel, print_help, get_icortex_kernel
2+
from icortex.cli import set_icortex_service, eval_cli
23
from icortex.exec import eval_prompt
34
import icortex.services

icortex/cli.py

Lines changed: 169 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import os
2+
import shlex
23
import sys
34
import argparse
4-
import toml
5-
import click
5+
from icortex.kernel import get_icortex_kernel
66
from jupyter_console.app import ZMQTerminalIPythonApp
7-
from icortex.services import service_dict, get_service
8-
from icortex.config import DEFAULT_SERVICE, DEFAULT_ICORTEX_CONFIG_PATH
7+
from icortex.services import get_available_services
8+
from icortex.defaults import DEFAULT_ICORTEX_CONFIG_PATH
99
from icortex.install import is_kernel_installed, main as install_kernel
10-
from icortex.kernel import ICortexKernel
10+
from icortex.config import ICortexConfig
1111

1212
# Jupyter devs did not make this easy
1313
# TODO: Make less hacky
@@ -18,83 +18,197 @@ def parse_command_line(self, argv=None):
1818
self.build_kernel_argv(self.extra_args)
1919

2020

21-
def initialize_config(path: str):
22-
sorted_services = sorted(
23-
[key for key, val in service_dict.items() if not val.hidden]
21+
def get_parser(prog=None):
22+
service_names = get_available_services()
23+
parser = argparse.ArgumentParser(add_help=False)
24+
if prog is not None:
25+
parser.prog = prog
26+
27+
subparsers = parser.add_subparsers(dest="command")
28+
29+
######################
30+
# Initialize ICortex #
31+
######################
32+
33+
# //init
34+
parser_init = subparsers.add_parser(
35+
"init",
36+
help="Initialize ICortex configuration in the current directory",
37+
add_help=False,
38+
)
39+
40+
parser_init.add_argument(
41+
"--force", action="store_true", help="Force overwrite an existing configuration"
2442
)
25-
sorted_services.remove(DEFAULT_SERVICE)
26-
sorted_services = [DEFAULT_SERVICE] + sorted_services
2743

28-
service_name = click.prompt(
29-
"Which code generation service would you like to use?\nOptions: "
30-
+ ", ".join(sorted_services)
31-
+ "\nDefault",
44+
parser_init.add_argument(
45+
"--config",
3246
type=str,
33-
default=DEFAULT_SERVICE,
47+
help="Path to the configuration TOML file.",
48+
default=DEFAULT_ICORTEX_CONFIG_PATH,
3449
)
3550

36-
try:
37-
service = get_service(service_name)
38-
except KeyError:
39-
print(f"Service does not exist: {service_name}")
40-
quit()
51+
##########################
52+
# Shell related commands #
53+
##########################
4154

42-
print(f"Selected service: {service_name}")
43-
skip_defaults = click.confirm("Use default options?", default=True)
44-
service_config = service.config_dialog(service, skip_defaults=skip_defaults)
55+
# //shell
56+
parser_shell = subparsers.add_parser(
57+
"shell",
58+
help="Start ICortex shell",
59+
add_help=False,
60+
)
4561

46-
toml_dict = {"service": service_name, service_name: {}}
47-
for key, val in service_config.items():
48-
toml_dict[service_name][key] = val
62+
########
63+
# Help #
64+
########
4965

50-
with open(path, "w") as f:
51-
toml.dump(toml_dict, f)
66+
# //help
67+
parser_help = subparsers.add_parser(
68+
"help",
69+
help="Print help",
70+
add_help=False,
71+
)
5272

73+
############################
74+
# Service related commands #
75+
############################
5376

54-
def get_parser():
55-
parser = argparse.ArgumentParser()
77+
# //service
78+
parser_service = subparsers.add_parser(
79+
"service",
80+
help="Set and configure code generation services",
81+
add_help=False,
82+
)
83+
parser_service_commands = parser_service.add_subparsers(
84+
dest="service_command",
85+
required=True,
86+
)
5687

57-
parser.add_argument(
58-
"-i",
59-
"--init",
60-
action="store_true",
61-
help="Initialize ICortex configuration file in the current directory",
88+
# //service set <service_name>
89+
parser_service_commands_set = parser_service_commands.add_parser(
90+
"set",
91+
help="Set the service to be used for code generation",
92+
add_help=False,
6293
)
63-
parser.add_argument(
64-
"-c",
65-
"--config",
94+
parser_service_commands_set.add_argument(
95+
"service_name",
96+
choices=service_names,
97+
help="Name of the service to be used for code generation",
98+
)
99+
100+
# //service show <service_name>
101+
parser_service_commands_show = parser_service_commands.add_parser(
102+
"show",
103+
help="Show current service",
104+
add_help=False,
105+
)
106+
107+
# //service help
108+
parser_service_commands_help = parser_service_commands.add_parser(
109+
"help",
110+
help="Print help for //service",
111+
add_help=False,
112+
)
113+
114+
# //service set-var <variable_name> <variable_value>
115+
parser_service_commands_set_var = parser_service_commands.add_parser(
116+
"set-var",
117+
help="Set a variable for the current service",
118+
add_help=False,
119+
)
120+
parser_service_commands_set_var.add_argument(
121+
"variable_name",
122+
help="Name of the variable to be changed",
123+
)
124+
parser_service_commands_set_var.add_argument(
125+
"variable_value",
66126
type=str,
67-
help="Path to the configuration TOML file.",
68-
default=DEFAULT_ICORTEX_CONFIG_PATH,
127+
help="New value for the variable",
128+
)
129+
130+
# //service init <service_name>
131+
# Used to re-spawn the config dialog if some config for the service
132+
# already exists
133+
parser_service_commands_init = parser_service_commands.add_parser(
134+
"init",
135+
help="Initialize the configuration for the given service",
136+
add_help=False,
137+
)
138+
parser_service_commands_init.add_argument(
139+
"service_name",
140+
choices=service_names,
141+
help="Name of the service to be used for code generation",
69142
)
70-
return parser
143+
if prog is not None:
144+
parser_init.prog = prog
145+
for action in parser._actions:
146+
if isinstance(action, argparse._SubParsersAction):
147+
for _, subparser in action.choices.items():
148+
subparser.prog = prog
71149

150+
return parser, parser_service
72151

73-
def read_config(path):
74-
return toml.load(open(path, "r"))
75152

153+
def set_icortex_service(config_path=DEFAULT_ICORTEX_CONFIG_PATH):
154+
kernel = get_icortex_kernel()
155+
if kernel is not None:
156+
return ICortexConfig(DEFAULT_ICORTEX_CONFIG_PATH).set_service()
157+
return False
76158

77-
def main(argv=None):
159+
160+
def main(argv=None, prog=None):
78161
if argv is None:
79162
argv = sys.argv[1:]
80163

81-
parser = get_parser()
164+
parser, parser_service = get_parser(prog=prog)
82165
args = parser.parse_args(argv)
83166

84167
# Install kernel if it's not already
85168
if not is_kernel_installed():
86169
install_kernel()
87170

88-
# If no config file exists, initialize it
89-
if args.init or not os.path.exists(args.config):
90-
initialize_config(args.config)
91-
# if args.init or not os.path.exists(DEFAULT_ICORTEX_CONFIG_PATH):
92-
# initialize_config(DEFAULT_ICORTEX_CONFIG_PATH)
93-
94-
# print(ICortexKernel.config_path)
95-
# Launch shell
96-
if not args.init:
97-
ZMQTerminalICortexApp.launch_instance()
171+
if "config" in args:
172+
config_path = args.config
173+
else:
174+
config_path = DEFAULT_ICORTEX_CONFIG_PATH
175+
176+
config = ICortexConfig(config_path)
177+
178+
if args.command == "init":
179+
# If no config file exists, initialize it
180+
if os.path.exists(config_path) and not args.force:
181+
print(f"The file {config_path} already exists. Use --force to overwrite.")
182+
else:
183+
config.init_config()
184+
elif args.command == "service":
185+
if args.service_command == "set":
186+
config.set_service_config(args.service_name)
187+
elif args.service_command == "set-var":
188+
config.set_service_var(args.variable_name, args.variable_value)
189+
elif args.service_command == "show":
190+
print(config.format_current_service())
191+
elif args.service_command == "init":
192+
config.set_service_config(args.service_name, hard_init=True)
193+
elif args.service_command == "help":
194+
parser_service.print_help()
195+
elif args.command == "help":
196+
parser.print_help()
197+
elif args.command == "shell" or args.command is None:
198+
kernel = get_icortex_kernel()
199+
if kernel is None:
200+
ZMQTerminalICortexApp.launch_instance()
201+
else:
202+
# print("The ICortex shell is already running, skipping.")
203+
parser.print_help()
204+
205+
206+
def eval_cli(prompt: str):
207+
argv = shlex.split(prompt)
208+
try:
209+
return main(argv=argv, prog="//")
210+
except SystemExit:
211+
return
98212

99213

100214
if __name__ == "__main__":

0 commit comments

Comments
 (0)