I am trying to create a python CLI tool for monitoring a specific process at a given interval of time.
I am trying to customize the message that gets printed out when a ValueError
is caught, while also trying to exit the program by using sys.exit(1)
, which can be found in the validate
function within example.py
. If I weren't to use sys.exit(1)
, the print
command within the main
function would've been executed.
Having that sorted out, I procceded with performing a unit test (using unittest), by using test_example.py
, for the specific program, to check if a SystemExit
is raised when a negative value is passed to the time
argument.
As such, how could I make it so that the assertRaise
for SystemExit
will result as true?
I'm using python 3.10.4 and argparse 1.1 .
# example.py
import argparse, sys
def parse_args(args):
parser = argparse.ArgumentParser()
parser.add_argument("-t", "--time", type=float, metavar=" ")
return parser.parse_args(args)
def validate(data):
try:
if data.time < 0:
raise ValueError
except ValueError:
print(f"Time has a negative value: {data.time}. Please use a positive value")
sys.exit(1)
def main():
parsed_data = parse_args(sys.argv[1:])
validate(parsed_data)
print(parsed_data.time)
if __name__ == '__main__':
main()
# test_example.py
import unittest
from example import parse_args, validate
class TestExemplu(unittest.TestCase):
def test_negative_value(self):
with self.assertRaises(SystemExit) as cm:
validate()
the_exception = cm.exception
self.assertEqual(the_exception.code, 1)
if __name__ == '__main__':
unittest.main()
This is the error that I get:
test_negative_value (test_example.TestExemplu) ... ERROR
======================================================================
ERROR: test_negative_value (test_example.TestExemplu)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\tester\Downloads\cli_mon_tool_1\test_example.py", line 16, in test_negative_value
validate()
TypeError: validate() missing 1 required positional argument: 'data'
----------------------------------------------------------------------
Ran 1 test in 0.002s
FAILED (errors=1)
I came up with this solution, according to these 2 links:
# example.py
import argparse, sys
debug = False
def parse_args(args):
parser = argparse.ArgumentParser()
parser.add_argument("-p", "--path", type=str, metavar=" ")
parser.add_argument("-t", "--time", type=float, metavar=" ")
return parser.parse_args(args)
def exceptionHandler(exception_type, exception, traceback, debug_hook=sys.excepthook):
'''Print user friendly error messages normally, full traceback if DEBUG on.
Adapted from http://stackoverflow.com/questions/27674602/hide-traceback-unless-a-debug-flag-is-set
'''
if debug:
print('\n*** Error:')
debug_hook(exception_type, exception, traceback)
else:
print("%s: %s" % (exception_type.__name__, exception))
sys.excepthook = exceptionHandler
def validate(data):
try:
if data.time < 0:
raise ValueError
except ValueError:
raise ValueError(f"Time has a negative value: {data.time}. Please use a positive value")
try:
if data.time == 0:
raise ValueError
except ValueError as e:
raise ValueError(f"Time has a value of zero. Please use a positive value")
def main():
parsed_data = parse_args(sys.argv[1:])
validate(parsed_data)
print(parsed_data.path)
print(parsed_data.time)
if __name__ == '__main__':
main()
# test_example.py
import unittest
from example import parse_args, validate
class TestExemplu(unittest.TestCase):
def test_negative_value(self):
parsed_data1 = parse_args(['-t', '-1'])
parsed_data2 = parse_args(['-t', '0'])
parsed_data3 = parse_args(['-t', '-1'])
self.assertRaises(ValueError, validate, parsed_data1)
self.assertRaises(ValueError, validate, parsed_data2)
try:
self.assertRaises(ValueError, validate, parsed_data2)
except:
pass
if __name__ == '__main__':
unittest.main()