Make my python command line program interactive with argparse - python

i'm trying to make my python program interactive in command line, user should be able to do stuff like :
python myprogram.py --create
then
python myprogram.py --send
The problem in this when is that the program stop and restart each time so i lose my variable and object that i created with the first command.
I'm using argparse on this way:
parser = argparse.ArgumentParser()
parser.add_argument('-c','--create' ,help='',action='store_true')
parser.add_argument('-s','--send',help='',action='store_true')
args = parser.parse_args()
if args.create:
create()
elif args.send :
send()
I don't want to stop the program between the command, how to do this ?
example : https://coderwall.com/p/w78iva

Here's a simple interactive script. I use argparse to parse the input lines, but otherwise it is not essential to the action. Still it can be an handy way of adding options to your 'create' command. For example, ipython uses argparse to handle its %magic commands:
import argparse
parser = argparse.ArgumentParser(prog='PROG', description='description')
parser.add_argument('cmd', choices=['create','delete','help','quit'])
while True:
astr = raw_input('$: ')
# print astr
try:
args = parser.parse_args(astr.split())
except SystemExit:
# trap argparse error message
print 'error'
continue
if args.cmd in ['create', 'delete']:
print 'doing', args.cmd
elif args.cmd == 'help':
parser.print_help()
else:
print 'done'
break
This could be stripped down to the while loop, the raw_input line, and your own evaluation of the astr variable.
The keys to using argparse here are:
parse_args can take a list of strings (the result of split()) instead of using the default sys.argv[1:].
if parse_args sees a problem (or '-h') it prints a message and tries to 'exit'. If you want to continue, you need to trap that error, hence the try block.
the output of parse_args is a simple namespace object. You access the arguments as attributes.
you could easily substitute your own parser.

The diffrence in cmd and argparse is that cmd is a "line-oriented command interpreter" while argparse is a parser for sys.argv.
Your example parses sys.argv that you pass while running your program and then if it gets the value you start a function and then quits.
argparse will only parse the sys.argv while running the program.
You could add some code to be able to work with the args you pass like a function or class or make in program menu that you could operate with raw_input.
Example:
class Main():
def __init__(self, create=None, send=None):
if create:
self.create(create)
elif send:
self.send(send)
option = raw_input('What do you want to do now?')
print option
def create(self, val):
print val
def send(self, val):
print val
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('-c','--create' ,help='',action='store_true')
parser.add_argument('-s','--send',help='',action='store_true')
args = parser.parse_args()
Main(args.create, args.send)
Other then that Python argparse and controlling/overriding the exit status code or python argparse - add action to subparser with no arguments? might help.
In the first it shows how you can override the quit and in the second how can you add subcommands or quitactions.

Related

Using sys.argv to retrieve different functions

So let's say I have these lines of code:
if __name__ == '__main__':
if '-h' in sys.argv:
show_help()
elif '-f' or 'function'in sys.argv:
print(function1)
elif '-n'or '-name' in sys.argv:
print(function2)
elif '-e' or '-extension'in sys.argv:
print(function3])
elif '-m' or '-missing'in sys.argv:
print(function4)
elif 'r' or '-range' in sys.argv:
print(function5)
else:
exit
The letters are supposed to be inputs from the user in the bash terminal.
Showing the help method works and it is able to show all of the strings.
The -f input works and shows the contents that I need in that function, however the code just spits out the content from function 1 and not from function2 and so on.
How do I get these different letters, -f, -n, -e, -m (if inputted) to carry out that function and spit out that information?
Also is there a more efficient way to do this without using argparse for a beginner Python scripter?
To test if any one of two values is in a list, you can't use the or operator with the in operator. You need to test each value separately using the in operator, like this:
if '-h' in sys.argv:
show_help()
elif '-f' in sys.argv or '-function' in sys.argv:
print(function1)
elif '-n' in sys.argv or '-name' in sys.argv:
print(function2)
elif '-e' in sys.argv or '-extension'in sys.argv:
print(function3])
elif '-m' in sys.argv or '-missing'in sys.argv:
print(function4)
elif '-r' in sys.argv or '-range' in sys.argv:
print(function5)
else:
exit
I highly suggest using argparse.
If you prefer not to, creating a dictionary of flags is also possible:
flags = {
'-h': show_help,
'-f': function1,
'-function': function1,
'-n': function2,
'-name': function2,
'-e': function3,
'-extension': function3,
'-m': function4,
'-missing': function4,
'-r': function5,
'-range': function5,
}
if __name__ == '__main__':
for flag in sys.argv:
print(flags[flag])
By creating a dictionary, you're able to just look up the keys.
It results in cleaner, faster, and more maintainable code.

python - adding a argument to execution script

consider I am having a following code in my bin as follows(filename: emp_dsb):
import sys
from employee_detail_collector.EmpCollector import main
if __name__ == '__main__':
sys.exit(main())
In my command line I will execute the "emp_dsb", so that above code will execute the main function from "employee_detail_collector.EmpCollector"
Code in (employee_detail_collector.EmpCollector) main():
def main():
try:
path = const.CONFIG_FILE
empdsb = EmpDashboard(path)
except SONKPIExceptions as e:
logger.error(e.message)
except Exception as e:
logger.error(e)
Now I need to add some argument here for emp_dsb, that is like "emp_dsb create_emp" should invoke a new set of functionalities for creating a employee, which is also needs to be added in same main()
someone look and let me know your ideas, If not clear let me know so that i will try to make it more clear.
the standard way to use command line arguments is to do this:
import sys
if __name__ == '__main__':
print(sys.argv)
read up on the doc of sys.argv.
then there are fancier ways like the built-in argparse and the 3rd party docopt or click.
I would personally use 'argparse' module.
Here is the link to a dead simple code sample.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo")
args = parser.parse_args()
print(args.echo)

Parsing arguments using argparse and mpi4py

I want to run a Python script in several parallel processes under MPI, and I need to pass command-line arguments. I'm using the argparse module in Python, but it's a little messy sometimes. If I don't specify the right arguments, all the processes complain, so I get many copies of the same error message.
I tried making only process 0 parse the arguments and then broadcast the results to the other processes, but then the other processes hang when the parsing fails and nothing gets broadcast.
How can I parse the command-line arguments, and print a readable message when the parsing fails?
The extra piece I needed was to wrap a try/finally around the argument parsing step in process 0. In the finally block, broadcast something to the other processes. If parsing failed, you will broadcast None, and they can all silently exit.
from mpi4py import MPI
from time import sleep
import argparse
def parseOptions(comm):
parser = argparse.ArgumentParser(
description='Print some messages.')
parser.add_argument('iteration_count', help='How many times', type=int)
parser.add_argument('message',
help='What to say',
nargs=argparse.OPTIONAL,
default='Hello, World!')
args = None
try:
if comm.Get_rank() == 0:
args = parser.parse_args()
finally:
args = comm.bcast(args, root=0)
if args is None:
exit(0)
return args
def main():
comm = MPI.COMM_WORLD # #UndefinedVariable
rank = comm.Get_rank()
size = comm.Get_size()
args = parseOptions(comm)
if rank == 0:
print args.message
for i in range(args.iteration_count):
if i%size == rank:
print '{} in rank {} started.'.format(i, rank)
sleep(.5)
print '...'
sleep(.5)
print '{} in rank {} ended.'.format(i, rank)
if __name__ == '__main__':
main()
I run the code with a command like this:
mpirun -np 4 python scratch.py 13
If you have an error case, it's usually easiest to just have the processes abort rather than trying to do something fancy to clean up. In your case, you could just have the origin process (rank 0) call abort and cause everyone else to quit:
comm.abort()
That way, you don't have everyone trying to match up the results. They just automatically abort.

calling functions from command prompt

Here is the extract of the script (untested)
def start_custer():
try:
myidentifier=mydict['DescribeClustersResponse']['DescribeClustersResult']['Clusters'][0]['ClusterIdentifier']
except IndexError:
conn.restore_from_cluster_snapshot('vi-mar5-deliveryreport-new', mysnapidentifier, availability_zone='us-east-1a')
def stop_cluster():
try:
myidentifier=mydict['DescribeClustersResponse']['DescribeClustersResult']['Clusters'][0]['ClusterIdentifier']
conn.delete_cluster(myidentifier, skip_final_cluster_snapshot=False, final_cluster_snapshot_identifier=myvar)
except:
print "error"
Are these functions technically (syntactically) correct?
How do I call them while calling the python script? I need to either start or stop cluster at a time, not both.
For your second question, I'd parse the command line via argparse:
import argparse
parser = argparse.ArgumentParser(description="Manage the cluster")
parser.add_argument("action", choices=["stop", "start"],
help="Action to perform")
args = parser.parse_args()
if args.action == "start":
start_cluster()
if args.action == "stop":
stop_cluster()
Others have shown you the best way to do this, but for the record, you can also do this from the command line:
python -c "import cluster; cluster.start_cluster()"
(assuming your module file is named cluster.py -- adjust the import statement accordingly if not)
This isn't as user-friendly as parsing the command line yourself but it'll do in a pinch.
1) It's Syntactically correct, if you have defined conn somewhere and imported it !
2)
def stop_cluster():
## Your code
def fun():
## your code
if __name__ == "__main__":
import sys
globals()[sys.argv[1]]()
Usage:
python2.7 test_syn.py fun
I have added a main function to your script which checks for command line args, then prompts you if no valid argument has been supplied:
import sys
def start_custer():
try:
myidentifier=mydict['DescribeClustersResponse']['DescribeClustersResult']['Clusters'][0]['ClusterIdentifier']
except IndexError:
conn.restore_from_cluster_snapshot('vi-mar5-deliveryreport-new', mysnapidentifier, availability_zone='us-east-1a')
def stop_cluster():
try:
myidentifier=mydict['DescribeClustersResponse']['DescribeClustersResult']['Clusters'][0]['ClusterIdentifier']
conn.delete_cluster(myidentifier, skip_final_cluster_snapshot=False, final_cluster_snapshot_identifier=myvar)
except:
print "error"
def main():
valid_args, proc = ['start','stop'], None
# check if cmd line args were passed in (>1 as sys.argv[0] is name of program)
if len(sys.argv) > 1:
if sys.argv[1].lower() in valid_args:
proc = sys.argv[1].lower()
# if a valid arg was passed in this has been stored in proc, if not prompt user
while not proc or proc not in valid_args:
print "\nPlease state which procedure you want to call, valid options are:", valid_args
proc = raw_input('>>> ').lower()
# prompt user if invalid
if proc not in valid_args:
print proc, 'is not a valid selection.'
if proc == 'start':
start_custer()
elif proc == 'stop':
stop_cluster()
# this makes the script automatically call main when starting up
if __name__ == '__main__':
main()
You can call this from the command line e.g. if you were in the same directory as the file (e.g. named cluster_ctrl.py) just:
python cluster_ctrl.py start

ArgumentParser -h (help) will not work

I cannot get ArgumentParser to work. What's wrong with the following:
import argparse
parser=argparse.ArgumentParser(description='''I wish this description would output''',
epilog='''Please out the epilog''')
parser.add_argument('-l', type=str, default='info', help='logging level. Default is info. Use debug if you have problems.')
args=parser.parse_args()
def main():
print("goodbye")
if __name__ == "__main__":
#main
main()
When I run myscript -h I see no help.
I am running Python 2.7 on Windows 7. I have Python on my path and also pathext set as:
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.py
The argsparse code never actually gets executed. By executing the script from the command line, you're calling main(), which simply prints and exits. You have to call parse_args() in the main() function for this to work.
import argparse
# Personally, I think these belong in the main()
# function as well, but they don't need to be.
parser = argparse.ArgumentParser(
description="I wish this description would output",
epilog="Please out the epilog"
)
parser.add_argument(
"-l",
type=str,
default="info",
help="logging level. Default is info. Use debug if you have problems."
)
def main():
args = parser.parse_args() # Parses arguments
print("goodbye")
if __name__ == "__main__":
main() # Calls main
Produces:
~/Desktop $ python untitled.py --help
usage: untitled.py [-h] [-l L]
I wish this description would output
optional arguments:
-h, --help show this help message and exit
-l L logging level. Default is info. Use debug if you have problems.
Please out the epilog
jcollado claims your code worked fine on Ubuntu--I find this very curious.
If you run this script from the command line you're going to just print 'goodbye', put the argparse code after if __name__ == "__main__":.
OK weird answer for this. The problem was resolved by calling the program as:
python myscript.py -h
If you add python to your path, set file associations and then just do:
myscript.py -h
it will not pick up the -h

Categories