Skip to content

Commit bf7f275

Browse files
authored
Merge pull request #184 from GATEOverflow/dev
Fix an issue with --help for individual scripts
2 parents 785a021 + 7ccaf7e commit bf7f275

File tree

3 files changed

+96
-103
lines changed

3 files changed

+96
-103
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.2.0
1+
1.1.1

mlc/main.py

Lines changed: 94 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,83 @@ def process_console_output(res, target, action, run_args):
115115
if default_parent is None:
116116
default_parent = Action()
117117

118-
# Main CLI function
118+
119+
log_flag_aliases = {'-v': '--verbose', '-s': '--silent'}
120+
log_levels = {'--verbose': logging.DEBUG, '--silent': logging.WARNING}
121+
122+
123+
def build_pre_parser():
124+
pre_parser = argparse.ArgumentParser(add_help=False)
125+
pre_parser.add_argument("action", nargs="?", help="Top-level action (run, build, help, etc.)")
126+
pre_parser.add_argument("target", choices=['run', 'script', 'cache', 'repo'], nargs="?", help="Target (repo, script, cache, ...)")
127+
pre_parser.add_argument("-h", "--help", action="store_true")
128+
return pre_parser
129+
130+
131+
def build_parser(pre_args):
132+
parser = argparse.ArgumentParser(prog="mlc", description="Manage repos, scripts, and caches.", add_help=False)
133+
subparsers = parser.add_subparsers(dest="command", required=not pre_args.help)
134+
135+
# General commands
136+
for action in ['run', 'pull', 'test', 'add', 'show', 'list', 'find', 'search', 'rm', 'cp', 'mv', 'help']:
137+
p = subparsers.add_parser(action, add_help=False)
138+
p.add_argument('target', choices=['repo', 'script', 'cache'])
139+
p.add_argument('details', nargs='?', help='Details or identifier (optional)')
140+
p.add_argument('extra', nargs=argparse.REMAINDER)
141+
142+
# Script-only
143+
for action in ['docker', 'experiment', 'doc', 'lint']:
144+
p = subparsers.add_parser(action, add_help=False)
145+
p.add_argument('target', choices=['script', 'run'])
146+
p.add_argument('details', nargs='?', help='Details or identifier (optional)')
147+
p.add_argument('extra', nargs=argparse.REMAINDER)
148+
149+
# Load cfg
150+
load_parser = subparsers.add_parser("load", add_help=False)
151+
load_parser.add_argument("target", choices=["cfg"])
152+
return parser
153+
154+
155+
def configure_logging(args):
156+
if hasattr(args, 'extra') and args.extra:
157+
args.extra[:] = [log_flag_aliases.get(a, a) for a in args.extra]
158+
for flag, level in log_levels.items():
159+
if flag in args.extra:
160+
logging.getLogger().setLevel(level)
161+
args.extra.remove(flag)
162+
163+
164+
def build_run_args(args):
165+
res = utils.convert_args_to_dictionary(getattr(args, 'extra', []))
166+
if res['return'] > 0:
167+
return res
168+
169+
run_args = res['args_dict']
170+
run_args['mlc_run_cmd'] = shlex.join(sys.argv)
171+
172+
if args.command in ['pull', 'rm', 'add', 'find'] and args.target == "repo":
173+
run_args['repo'] = args.details
174+
175+
if args.command in ['docker', 'experiment', 'doc', 'lint'] and args.target == "run":
176+
run_args['target'] = 'script'
177+
args.target = "script"
178+
179+
if args.details and not utils.is_uid(args.details) and not run_args.get("tags") and args.target in ["script", "cache"]:
180+
run_args['tags'] = args.details
181+
182+
if not run_args.get('details') and args.details:
183+
run_args['details'] = args.details
184+
185+
if args.command in ["cp", "mv"]:
186+
run_args['target'] = args.target
187+
if args.details:
188+
run_args['src'] = args.details
189+
if args.extra:
190+
run_args['dest'] = args.extra[0]
191+
192+
return run_args
193+
194+
119195
def main():
120196
"""
121197
MLCFlow is a CLI tool for managing repos, scripts, and caches.
@@ -154,15 +230,16 @@ def main():
154230
mlc run script --help
155231
mlc pull repo -h
156232
"""
157-
158-
# First level parser for showing help
159-
pre_parser = argparse.ArgumentParser(add_help=False)
160-
pre_parser.add_argument("action", nargs="?", help="Top-level action (run, build, help, etc.)")
161-
pre_parser.add_argument("target", choices=['run', 'script', 'cache', 'repo'], nargs="?", help="Potential target (repo, script, cache, ...)")
162-
pre_parser.add_argument("-h", "--help", action="store_true")
233+
pre_parser = build_pre_parser()
163234
pre_args, remaining_args = pre_parser.parse_known_args()
164235

165-
if pre_args.help and not any("--tags" in arg for arg in remaining_args):
236+
parser = build_parser(pre_args)
237+
args = parser.parse_args() if remaining_args or pre_args.target else pre_args
238+
239+
configure_logging(args)
240+
run_args = build_run_args(args) if hasattr(args, "command") else {}
241+
242+
if pre_args.help and not "tags" in run_args:
166243
help_text = ""
167244
if pre_args.target == "run":
168245
if pre_args.action == "docker":
@@ -196,104 +273,20 @@ def main():
196273
if help_text != "":
197274
print(help_text)
198275
sys.exit(0)
199-
200-
# parser for execution of the automation scripts
201-
parser = argparse.ArgumentParser(prog='mlc', description='A CLI tool for managing repos, scripts, and caches.', add_help=False)
202-
203-
# Subparsers are added to main parser, allowing for different commands (subcommands) to be defined.
204-
# The chosen subcommand will be stored in the "command" attribute of the parsed arguments.
205-
subparsers = parser.add_subparsers(dest='command', required=True)
206-
207-
# Script and Cache-specific subcommands
208-
for action in ['run', 'pull', 'test', 'add', 'show', 'list', 'find', 'search', 'rm', 'cp', 'mv']:
209-
action_parser = subparsers.add_parser(action, add_help=False)
210-
action_parser.add_argument('target', choices=['repo', 'script', 'cache'], help='Target type (repo, script, cache).')
211-
# the argument given after target and before any extra options like --tags will be stored in "details"
212-
action_parser.add_argument('details', nargs='?', help='Details or identifier (optional for list).')
213-
action_parser.add_argument('extra', nargs=argparse.REMAINDER, help='Extra options (e.g., -v)')
214-
215-
# Script specific subcommands
216-
for action in ['docker', 'experiment', 'doc', 'lint']:
217-
action_parser = subparsers.add_parser(action, add_help=False)
218-
action_parser.add_argument('target', choices=['script', 'run'], help='Target type (script).')
219-
# the argument given after target and before any extra options like --tags will be stored in "details"
220-
action_parser.add_argument('details', nargs='?', help='Details or identifier (optional for list).')
221-
action_parser.add_argument('extra', nargs=argparse.REMAINDER, help='Extra options (e.g., -v)')
222-
223-
for action in ['load']:
224-
load_parser = subparsers.add_parser(action, add_help=False)
225-
load_parser.add_argument('target', choices=['cfg'], help='Target type (cfg).')
226-
227-
# Parse arguments
228-
args = parser.parse_args()
229276

230-
#logger.info(f"Args = {args}")
231-
232-
# set log level for MLCFlow if -v/--verbose or -s/--silent is specified
233-
log_flag_aliases = {
234-
'-v': '--verbose',
235-
'-s': '--silent'
236-
}
237-
238-
log_levels = {
239-
'--verbose': logging.DEBUG,
240-
'--silent': logging.WARNING
241-
}
242-
243-
# Modify args.extra in place
244-
args.extra[:] = [log_flag_aliases.get(arg, arg) for arg in args.extra]
277+
action = get_action(args.target, default_parent)
245278

246-
# Set log level based on the first matching flag
247-
for flag, level in log_levels.items():
248-
if flag in args.extra:
249-
logger.setLevel(level)
250-
args.extra.remove(flag)
279+
if not action or not hasattr(action, args.command):
280+
logging.error("Error: '%s' is not supported for %s.", args.command, args.target)
281+
sys.exit(1)
251282

252-
res = utils.convert_args_to_dictionary(args.extra)
283+
method = getattr(action, args.command)
284+
res = method(run_args)
253285
if res['return'] > 0:
254-
return res
255-
256-
run_args = res['args_dict']
257-
258-
run_args['mlc_run_cmd'] = " ".join(shlex.quote(arg) for arg in sys.argv)
259-
260-
if hasattr(args, 'repo') and args.repo:
261-
run_args['repo'] = args.repo
262-
263-
if args.command in ['pull', 'rm', 'add', 'find']:
264-
if args.target == "repo":
265-
run_args['repo'] = args.details
266-
267-
if args.command in ['docker', 'experiment', 'doc', 'lint']:
268-
if args.target == "run":
269-
run_args['target'] = 'script' #allowing run to be used for docker run instead of docker script
270-
args.target = "script"
271-
272-
if hasattr(args, 'details') and args.details and not utils.is_uid(args.details) and not run_args.get("tags") and args.target in ["script", "cache"]:
273-
run_args['tags'] = args.details
286+
logging.error(res.get('error', f"Error in {action}"))
287+
raise Exception(f"An error occurred {res}")
274288

275-
if not run_args.get('details') and args.details:
276-
run_args['details'] = args.details
277-
278-
if args.command in ["cp", "mv"]:
279-
run_args['target'] = args.target
280-
if hasattr(args, 'details') and args.details:
281-
run_args['src'] = args.details
282-
if hasattr(args, 'extra') and args.extra:
283-
run_args['dest'] = args.extra[0]
284-
285-
# Get the action handler for other commands
286-
action = get_action(args.target, default_parent)
287-
# Dynamically call the method (e.g., run, list, show)
288-
if action and hasattr(action, args.command):
289-
method = getattr(action, args.command)
290-
res = method(run_args)
291-
if res['return'] > 0:
292-
logger.error(res.get('error', f"Error in {action}"))
293-
raise Exception(f"""An error occurred {res}""")
294-
process_console_output(res, args.target, args.command, run_args)
295-
else:
296-
logger.error(f"Error: '{args.command}' is not supported for {args.target}.")
289+
process_console_output(res, args.target, args.command, run_args)
297290

298291
if __name__ == '__main__':
299292
main()

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "mlcflow"
7-
version = "1.0.23"
7+
version = "1.1.1"
88

99

1010

0 commit comments

Comments
 (0)