Skip to content

Instantly share code, notes, and snippets.

@mpkocher
Last active August 29, 2015 13:56
Show Gist options
  • Save mpkocher/9073529 to your computer and use it in GitHub Desktop.
Save mpkocher/9073529 to your computer and use it in GitHub Desktop.
Commandline Subparser with Validation
import os
import sys
import argparse
import logging
__version__ = '0.1'
log = logging.getLogger(__name__)
def adder(a, b):
"""Mock lib code that should be imported via mypackage.awesome."""
print a + b
def divider(a, b):
"""Mock lib code that should be imported."""
print a / float(b)
return 0
def _validate_number(v):
"""Validating function for int and floats"""
try:
n = int(v)
return n
except ValueError:
n = float(v)
return n
def _validate_non_zero_number(n):
n = _validate_number(n)
if n != 0:
return n
else:
raise ValueError("Unable to divide by zero.")
def _adder(args):
"""
Simple wrapping layer to not mix the argparsing IO layer into the lib
code. The lib code should always be importable.
"""
adder(args.a, args.b)
return 0
def _divider(args):
divider(args.a, args.b)
return 0
def get_parser():
"""Returns an argparser.ArgumentParser instance that uses subparsers"""
parser = argparse.ArgumentParser(description='Simple example',
version=__version__)
sp = parser.add_subparsers(help='commands')
add_p = sp.add_parser('add', help="Add two numbers")
add_p.add_argument('a', type=_validate_number, help="A number")
add_p.add_argument('b', type=_validate_number, help='A number')
add_p.set_defaults(func=_adder)
div_p = sp.add_parser('divide', help="Divide two numbers")
div_p.add_argument('a', type=_validate_number, help="A number")
div_p.add_argument('b', type=_validate_non_zero_number, help="A non-zero number")
div_p.set_defaults(func=_divider)
return parser
def main(args_list):
"""Main point of entry"""
p = get_parser()
args = p.parse_args(args_list)
rcode = args.func(args)
return rcode
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
import os
import logging
import unittest
import shlex
import example_validation_subparsers
log = logging.getLogger(__name__)
def _split(raw_args):
"""Split and log the results"""
args_list = shlex.split(raw_args)
log.debug("raw args '{r}' to arg list {a}".format(a=args_list, r=raw_args))
return args_list
class TestAdderMain(unittest.TestCase):
def test_basic(self):
raw_args = 'add 1 2.0'
args_list = _split(raw_args)
rcode = example_subparsers.main(args_list)
self.assertEqual(rcode, 0)
class TestDivideMain(unittest.TestCase):
def test_basic(self):
raw_args = 'divide 1 2.0'
args_list = _split(raw_args)
rcode = example_subparsers.main(args_list)
self.assertEqual(rcode, 0)
def test_divide_by_zero(self):
raw_args = 'divide 1 0'
args_list = _split(raw_args)
with self.assertRaises(SystemExit) as e:
log.info(e)
example_subparsers.main(args_list)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment