Skip to content

Commit

Permalink
cmd_line: update to latest version
Browse files Browse the repository at this point in the history
  • Loading branch information
joseph-zhong committed May 6, 2019
1 parent 62d7dd4 commit fe0abd7
Showing 1 changed file with 73 additions and 48 deletions.
121 changes: 73 additions & 48 deletions cmd_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,42 +8,20 @@
"""
import argparse
import inspect
import logging
import subprocess
from types import GeneratorType

import src.utils.utility as _util

_logger = _util.getLogger("CMD Line")

def runCmd(cmd, logger=None, stopOnFail=True):
if logger is None:
logger = _logger
else:
assert isinstance(logger, logging.Logger)

logger.info("Running '%s'", cmd)
# output = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT, shell=True)
# print output
# ret = subprocess.call(cmd.split(), shell=True)
# if ret != 0:
# logger.error("'%s' returned with error code: '%s'", cmd, ret)
# logger.debug("Traceback: '%s'", traceback.format_exc())
# if stopOnFail:
# sys.exit(ret)
# else:
# logger.info("'{}' Success!".format(cmd))
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=False)
proc_stdout = process.communicate()[0].strip()
print(proc_stdout)
logger.info("Completed running '%s", cmd)
_logger = _util.get_logger(__file__)


def _str_to_bool(s):
"""Convert string to bool (in argparse context)."""
if s.lower() not in ['true', 'false']:
raise ValueError('Need bool; got %r' % s)
return {'true': True, 'false': False}[s.lower()]


def add_boolean_argument(parser, name, default=False):
group = parser.add_mutually_exclusive_group()
group.add_argument(
Expand All @@ -56,27 +34,33 @@ def add_boolean_argument(parser, name, default=False):
dest=name,
action='store_false')


def parseArgsForClassOrScript(fn):
assert inspect.isfunction(fn) or inspect.ismethod(fn)

spec = inspect.getargspec(fn)
sig = inspect.signature(fn)

parser = argparse.ArgumentParser()
for i, arg in enumerate(spec.args):
if arg == 'self' or arg == 'logger':
for arg_name, arg in sig.parameters.items():
if arg_name == 'self' or arg_name == 'logger':
continue

# If index is greater than the last var with a default, it's required.
numReq = len(spec.args) - len(spec.defaults)
required = i < numReq
default = spec.defaults[i - numReq] if not required else None
# Arguments are required or not required,
# and have either an annotation or default value.
# By default, args are parsed as strings if not otherwise specified.
if isinstance(default, bool):
parser.add_argument("--" + arg, default=default, action='store_true')
elif isinstance(default, (tuple, list, GeneratorType)):
parser.add_argument("--" + arg, default=default, nargs="+", help="Tuple of " + arg, required=False)
# REVIEW josephz: Is there a better way to determine if it is a positional/required argument?
required = arg.default is inspect.Parameter.empty
default = arg.default if arg.default is not inspect.Parameter.empty else None
type_ = arg.annotation if arg.annotation is not inspect.Parameter.empty else type(default) if default is not None else str

if type_ is bool:
# REVIEW josephz: This currently has a serious flaw in that clients may only set positive boolean flags.
# The way to fix this would be to use the annotation to parse the input as a boolean.
parser.add_argument("--" + arg_name, default=default, action='store_true')
elif type_ in (tuple, list, GeneratorType):
parser.add_argument("--" + arg_name, default=default, type=type_, nargs="+", help="Tuple of " + arg_name)
else:
parser.add_argument("--" + arg, default=default, type=type(default) if default is not None else str)
parser.add_argument("--" + arg_name, default=default, type=type_, required=required)

parser.add_argument("-v", "--verbosity",
default=_util.DEFAULT_VERBOSITY,
Expand All @@ -91,24 +75,65 @@ def parseArgsForClassOrScript(fn):
argv = parser.parse_args()
argsToVals = vars(argv)

# Print args for any verbosity greater than CRITICAL.
if argv.verbosity > 0 or argv.help:
if argv.verbosity >= 0 or hasattr(argv, 'help'):
docstr = inspect.getdoc(fn)
if docstr is None:
print(
"""WARNING:
Please write documentation :)
""")
"WARNING: Please write documentation :)"
print()
print(docstr.strip())
print()
print("Arguments and corresponding default or set values")
for arg in spec.args:
if arg == 'self' or arg == 'logger' or arg not in argsToVals:
for arg_name in sig.parameters:
if arg_name == 'self' or arg_name == 'logger' or arg_name not in argsToVals:
continue
print("\t{}={}".format(arg, argsToVals[arg] if argsToVals[arg] is not None else ""))
print("\t{}={}".format(arg_name, argsToVals[arg_name] if argsToVals[arg_name] is not None else ""))
print()

# parser.print_help()

return argv

def test_cmdline(required,
required_anno: int,
required_anno_tuple: tuple,
not_required="Test",
not_required_bool=False,
not_required_int=123,
not_required_float=123.0,
not_required_tuple=(1,2,3),
not_required_str="123",
not_required_None=None,
):
"""
:param required: A required, unannotated parameter.
:param required_anno: A required, annotated int parameter.
:param required_anno_tuple: A required, annotated tuple parameter.
:param not_required: A required, default-string parameter.
:param not_required_bool: A not-required, default-string parameter.
:param not_required_int: A not-required, default-int parameter.
:param not_required_float: A not-required, default-float parameter.
:param not_required_tuple: A not-required, default-tuple parameter.
:param not_required_str: A not-required, default-string parameter.
:param not_required_None: A not-required, default-string parameter.
"""
print("required:", required)
print("required_anno: ", required_anno)
print("required_anno_tuple:", required_anno_tuple)
print("not_required: ", not_required)
print("not_required_bool:", not_required_bool)
print("not_required_int:", not_required_int)
print("not_required_float:", not_required_float)
print("not_required_tuple:", not_required_tuple)
print("not_required_str:", not_required_str)
print("not_required_None:", not_required_None)

def main():
global _logger
args = parseArgsForClassOrScript(test_cmdline)
varsArgs = vars(args)
varsArgs.pop('verbosity', _util.DEFAULT_VERBOSITY)
_logger.info("Passed arguments: '{}'".format(varsArgs))
test_cmdline(**varsArgs)

if __name__ == '__main__':
main()

0 comments on commit fe0abd7

Please sign in to comment.