I'm fairly new to python and I'm stuck on how to structure my simple script when using command line arguments.
The purpose of the script is to automate some daily tasks in my job relating to sorting and manipulating images.
I can specify the arguments and get them to call the relevant functions, but i also want to set a default action when no arguments are supplied.
Here's my current structure.
parser = argparse.ArgumentParser()
parser.add_argument("-l", "--list", help="Create CSV of images", action="store_true")
parser.add_argument("-d", "--dimensions", help="Copy images with incorrect dimensions to new directory", action="store_true")
parser.add_argument("-i", "--interactive", help="Run script in interactive mode", action="store_true")
args = parser.parse_args()
if args.list:
func1()
if args.interactive:
func2()
if args.dimensions:
func3()
But when I supply no arguments nothing will be called.
Namespace(dimensions=False, interactive=False, list=False)
What i want is some default behaviour if no arguements are supplied
if args.list:
func1()
if args.interactive:
func2()
if args.dimensions:
func3()
if no args supplied:
func1()
func2()
func3()
This seems like it should be fairly easy to achieve but I'm lost on the logic of how to detect all arguments are false without looping through the arguments and testing if all are false.
Multiple arguments are valid together, that is why I didn't go down the elif route.
Here is my updated code taking into account the answer from @unutbu
it doesn't seem ideal as everything is wrapped in an if statement but in the short term i couldn't find a better solution. I'm happy to accept the answer from @unutbu, any other improvements offered would be appreciated.
lists = analyseImages()
if lists:
statusTable(lists)
createCsvPartial = partial(createCsv, lists['file_list'])
controlInputParital = partial(controlInput, lists)
resizeImagePartial = partial(resizeImage, lists['resized'])
optimiseImagePartial = partial(optimiseImage, lists['size_issues'])
dimensionIssuesPartial = partial(dimensionIssues, lists['dim_issues'])
parser = argparse.ArgumentParser()
parser.add_argument(
"-l", "--list",
dest='funcs', action="append_const", const=createCsvPartial,
help="Create CSV of images",)
parser.add_argument(
"-c", "--convert",
dest='funcs', action="append_const", const=resizeImagePartial,
help="Convert images from 1500 x 2000px to 900 x 1200px ",)
parser.add_argument(
"-o", "--optimise",
dest='funcs', action="append_const", const=optimiseImagePartial,
help="Optimise filesize for 900 x 1200px images",)
parser.add_argument(
"-d", "--dimensions",
dest='funcs', action="append_const", const=dimensionIssuesPartial,
help="Copy images with incorrect dimensions to new directory",)
parser.add_argument(
"-i", "--interactive",
dest='funcs', action="append_const", const=controlInputParital,
help="Run script in interactive mode",)
args = parser.parse_args()
if not args.funcs:
args.funcs = [createCsvPartial, resizeImagePartial, optimiseImagePartial, dimensionIssuesPartial]
for func in args.funcs:
func()
else:
print 'No jpegs found'
You could append_const
the funcs to an attribute, args.funcs
, and then use one if-statement to supply the default behavior if no options are set:
if not args.funcs:
args.funcs = [func1, func2, func3]
import argparse
def func1(): pass
def func2(): pass
def func3(): pass
parser = argparse.ArgumentParser()
parser.add_argument(
"-l", "--list",
dest='funcs', action="append_const", const=func1,
help="Create CSV of images", )
parser.add_argument(
"-i", "--interactive",
dest='funcs', action="append_const", const=func2,
help="Run script in interactive mode",)
parser.add_argument(
"-d", "--dimensions",
dest='funcs', action='append_const', const=func3,
help="Copy images with incorrect dimensions to new directory")
args = parser.parse_args()
if not args.funcs:
args.funcs = [func1, func2, func3]
for func in args.funcs:
print(func.func_name)
func()
% test.py
func1
func2
func3
% test.py -d
func3
% test.py -d -i
func3
func2
Note that, unlike your original code, this allows the user to control the order the functions are called:
% test.py -i -d
func2
func3
That may or may not be desireable.
In response to Update 2:
Your code will work just fine. However, here is another way you could organize it:
Instead of nesting the main program inside an if
clause, you could
use
if not lists:
sys.exit('No jpegs found')
# put main program here, unnested
sys.exit will print No jpegs found
to stderr
and terminate with exit code 1.
Although I originally suggested using functools.partial
, another -- perhaps simpler -- way now comes to mind: Instead of
for func in args.funcs:
func()
we could say
for func, args in args.funcs:
func(args)
All we need to do is store a tuple (func, args)
in args.func
instead of the function alone.
For example:
import argparse
import sys
def parse_args(lists):
funcs = {
'createCsv': (createCsv, lists['file_list']),
'resizeImage': (resizeImage, lists['resized']),
'optimiseImage': (optimiseImage, lists['size_issues']),
'dimensionIssues': (dimensionIssues, lists['dim_issues']),
'controlInput': (controlInput, lists)
}
parser = argparse.ArgumentParser()
parser.add_argument(
"-l", "--list",
dest='funcs', action="append_const", const=funcs['createCsv'],
help="Create CSV of images",)
parser.add_argument(
"-c", "--convert",
dest='funcs', action="append_const", const=funcs['resizeImage'],
help="Convert images from 1500 x 2000px to 900 x 1200px ",)
parser.add_argument(
"-o", "--optimise",
dest='funcs', action="append_const", const=funcs['optimiseImage'],
help="Optimise filesize for 900 x 1200px images",)
parser.add_argument(
"-d", "--dimensions",
dest='funcs', action="append_const", const=funcs['dimensionIssues'],
help="Copy images with incorrect dimensions to new directory",)
parser.add_argument(
"-i", "--interactive",
dest='funcs', action="append_const", const=funcs['controlInput'],
help="Run script in interactive mode",)
args = parser.parse_args()
if not args.funcs:
args.funcs = [funcs[task] for task in
('createCsv', 'resizeImage', 'optimiseImage', 'dimensionIssues')]
return args
if __name__ == '__main__':
lists = analyseImages()
if not lists:
sys.exit('No jpegs found')
args = parse_args(lists)
statusTable(lists)
for func, args in args.funcs:
func(args)
You can handle this by checking if the number of args equals 1. meaning only your python command was passed.
import argparse
import sys
parser = argparse.ArgumentParser()
parser.add_argument("-l", "--list", help="Create CSV of images", action="store_true")
parser.add_argument("-d", "--dimensions", help="Copy images with incorrect dimensions to new directory", action="store_true")
parser.add_argument("-i", "--interactive", help="Run script in interactive mode", action="store_true")
args = parser.parse_args()
if len(sys.argv)==1:
# display help message when no args are passed.
parser.print_help()
sys.exit(1)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With