amanuensis/amanuensis/cli/helpers.py
2020-01-18 11:51:54 -08:00

112 lines
3.3 KiB
Python

# Standard library imports
from argparse import ArgumentParser, Namespace
from functools import wraps
# These function wrappers allow us to use the same function for executing a
# command and for configuring it. This keeps command arg configuration close to
# where the command is defined and allows the main parser to use the same
# function to both set up and execute commands.
def add_argument(*args, **kwargs):
"""Passes the given args and kwargs to subparser.add_argument"""
def argument_adder(command):
second_layer = command.__dict__.get('wrapper', False)
@wraps(command)
def augmented_command(cmd_args):
if type(cmd_args) is ArgumentParser:
cmd_args.add_argument(*args, **kwargs)
if type(cmd_args) is not ArgumentParser or second_layer:
command(cmd_args)
augmented_command.__dict__['wrapper'] = True
return augmented_command
return argument_adder
def no_argument(command):
"""Noops for subparsers"""
@wraps(command)
def augmented_command(cmd_args):
if type(cmd_args) is not ArgumentParser:
command(cmd_args)
return augmented_command
# Wrapper for commands requiring lexicon or username options
def requires(arg, metavar, dest, fallback, help):
"""Subparser fallback for -u and -n options"""
def req_checker(command):
@wraps(command)
def augmented_command(cmd_args):
if type(cmd_args) is ArgumentParser:
cmd_args.add_argument(arg, metavar=metavar, dest=dest, help=help)
if command.__dict__.get('wrapper', False):
command(cmd_args)
if type(cmd_args) is Namespace:
base_val = hasattr(cmd_args, fallback) and getattr(cmd_args, fallback)
subp_val = hasattr(cmd_args, dest) and getattr(cmd_args, dest)
val = subp_val or base_val or None
if not val:
import config
config.logger.error("This command requires {}".format(arg))
return -1
setattr(cmd_args, dest, val)
command(cmd_args)
augmented_command.__dict__['wrapper'] = True
return augmented_command
return req_checker
requires_lexicon = requires("-n", "LEXICON", "lexicon", "tl_lexicon",
"Specify a lexicon to operate on")
requires_username = requires("-u", "USERNAME", "username", "tl_username",
"Specify a user to operate on")
# Helpers for common command tasks
CONFIG_GET_ROOT_VALUE = object()
def config_get(cfg, pathspec):
"""
Performs config --get for a given config
cfg is from a with json_ro context
path is the full pathspec, unsplit
"""
import json
from config import logger
if pathspec is CONFIG_GET_ROOT_VALUE:
path = []
else:
path = pathspec.split(".")
for spec in path:
if spec not in cfg:
logger.error("Path not found: {}".format(pathspec))
return -1
cfg = cfg.get(spec)
print(json.dumps(cfg, indent=2))
def config_set(cfg, set_tuple):
"""
Performs config --set for a given config
config is from a with json_rw context
set_tuple is a tuple of the pathspec and the value
"""
import json
from config import logger
pathspec, value = set_tuple
if not pathspec:
logger.error("Path must be non-empty")
path = pathspec.split('.')
try:
value = json.loads(value)
except:
pass # Leave value as string
for spec in path[:-1]:
if spec not in cfg:
logger.error("Path not found")
return -1
cfg = cfg.get(spec)
key = path[-1]
if key not in cfg:
logger.error("Path not found")
return -1
cfg[key] = value