87 lines
2.5 KiB
Python
87 lines
2.5 KiB
Python
import inspect
|
|
import sys
|
|
import os
|
|
from pargv import parse_args
|
|
|
|
|
|
def magicli(exclude=['main'], help_message=True, glbls=None, argv=None):
|
|
"""
|
|
Get all functions from calling file and interprets them as CLI commands.
|
|
Parses command line arguments for function to call
|
|
and calls it with all specified arguments.
|
|
Displays a help message and exits if the --help flag is set
|
|
or if no callable function is found.
|
|
Errors out with a TypeError if the specified arguments are invalid.
|
|
"""
|
|
glbls = glbls if glbls else inspect.currentframe().f_back.f_globals
|
|
argv = argv if argv else sys.argv
|
|
app_name, args, kwargs = format_args(argv)
|
|
|
|
functions = [f for f in filter_functions(glbls) if f.__name__ not in exclude]
|
|
|
|
if help_message and 'help' in kwargs:
|
|
print_help_and_exit(app_name, functions)
|
|
|
|
possible_commands = [f.__name__ for f in functions]
|
|
function_name = None
|
|
|
|
if len(args) and args[0] in possible_commands:
|
|
function_name = args[0]
|
|
args = args[1:]
|
|
elif app_name in possible_commands:
|
|
function_name = app_name
|
|
else:
|
|
print_help_and_exit(app_name, functions)
|
|
|
|
function_to_call = glbls.get(function_name)
|
|
|
|
try:
|
|
function_to_call(*args, **kwargs)
|
|
except TypeError:
|
|
pass
|
|
|
|
|
|
def format_args(argv):
|
|
args, kwargs = parse_args(argv)
|
|
app_name = os.path.basename(args[0])
|
|
args = args[1:]
|
|
return app_name, args, kwargs
|
|
|
|
|
|
def filter_functions(args):
|
|
"""
|
|
Gets list of functions from the globals variable of a specific module (default: __main__).
|
|
"""
|
|
return [v for v in args.values() if inspect.isfunction(v) and v.__module__ == args['__name__']]
|
|
|
|
|
|
def print_help_and_exit(app_name, functions):
|
|
"""
|
|
Print the help message based on functions contained in the calling file.
|
|
Exits after displaying the help message.
|
|
"""
|
|
print('Usage:')
|
|
for f in functions:
|
|
words = []
|
|
if app_name != f.__name__:
|
|
words.append(app_name)
|
|
words.append(f.__name__)
|
|
specs = inspect.getfullargspec(f)
|
|
words += ['--' + arg for arg in specs.args]
|
|
print(' '*4 + ' '.join(words))
|
|
exit()
|
|
|
|
|
|
def first_calling_frame():
|
|
for s in reversed(inspect.stack()):
|
|
if s.code_context == None:
|
|
continue
|
|
if s.code_context[0].startswith('import magicli'):
|
|
return s.frame
|
|
return None
|
|
|
|
|
|
frame = first_calling_frame()
|
|
if frame != None:
|
|
magicli(glbls=frame.f_globals)
|