Choose multiple optional arguments with argparse in Python 3 - python

I am using argparse in Python 3 to accept command-line arguments into a script.
import argparse
cli_argparser = argparse.ArgumentParser(description='')
cli_argparser.add_argument('-n', '--number', type=int, help="Pass a number 'n' to script.", required=False)
cli_argparser.add_argument('-q', '--query', help="Pass a query to the script", required=False)
cli_argparser.add_argument('-o', '--outfile', help="Saves the output to an external file.", required=False)
cli_args = cli_argparser.parse_args()
if (cli_args.number):
print ("\n--number has the value '" + str(cli_args.number) + "'\n")
elif (cli_args.query):
print ("\n--query has the value '" + cli_args.query + "'\n")
elif (cli_args.outfile):
print ("\n--output has the value '" + cli_args.outfile + "'\n")
else:
print ("\nNo Arguments passed. Set or Use a default value...\n")
Is there a way to make sure that if one specific argument is selected, another one MUST be specified? For instance, if -o is specified, it must also contain -n before or after -o.
I tried adding an if condition, like so:
if (cli_args.number):
print ("\n--number has the value '" + str(cli_args.number) + "'\n")
elif (cli_args.query):
print ("\n--query has the value '" + cli_args.query + "'\n")
elif (cli_args.outfile):
if (cli_args.number):
print ("\n--output has the value '" + cli_args.outfile + "'\n")
else:
print ("\n--number not specified. Exit..")
else:
print ("\nNo Arguments passed. Set or Use a default value...\n")
The result is that, if only -o is specified, the script exits (as expected), however, if -n is added, the first condition is True.
$ python test.py -o output.txt
--number not specified. Exit..
$ python test.py -o output.txt -n 100
--number has the value '100'
How would I modify this such that if only -n is specified, the 1st condition is true and if -o is specified, it requires -n too and then executes the 3rd condition? Would something like cli_args.number AND cli_args.outfile work? Or is there an in-built function in argparse for this?

elif (cli_args.outfile):
if (cli_args.number):
print ("\n--output has the value '" + cli_args.outfile + "'\n")
This branch of logic is unreachable in your code as whenever cli_args.number is true, it would have fulfilled the first condition in your if ... else branch.
You could check for outfile and number first, or you could change the logic in the first if statement to if number and not outfile.

Related

I need to input the print from this function into a tkinter page

I have this function that prints 25 lines of text and I need to input it in my tkinter page, but ever time it doesn't seem to work.
I've tried using text.input but it didn't seeem to work
This is the function I need to print:
def decode(secretmessage):
for key in range(len(alphabet)):
newAlp = alphabet[key:] + alphabet[:key]
attempt = ""
for i in range(len(message)):
index = alphabet.find(message[i])
if index < 0:
attempt += message[i]
else:
attempt += newAlp[index]
print("Key: " + str(key) + " - " + attempt)
print()
This is what I tried:
def finalprint (uncoded):
print("Key: " + str(key) + " - " + attempt)
print()
text = Text.insert(root, finalprint(message), width=450, height=450)
It doesn't work to show up for some reason.
The print command prints the given text to console. It does returns None
Your finalprint function also returns None while Text.insert expects a string as an input.
Instead of printing the output you can store the values into a string.
def finalprint(uncoded): ## may need different inputs as key and attempts are not in scope
string = ""
string = string + "Key: " + str(key) + " - " + attempts + "\n"
return string
However the input to the finalprint function is uncoded while the variables used in it are key and attempts. You may need to pass in more information to the function for it to work like you have it written.

Executing python functions with multiple arguments in terminal

I have written a python function which takes multiple arguments and i want it to run from terminal but it's not working. what am I doing wrong?
counting.py script:
def count (a, b):
word = False
a = " " + a + " "
b = " " + b + " "
result = 0
for i in range (len (a)-1):
if a[i] == " " and a[i+1] != " ":
word = True
result += 1
else:
word = False
for i in range (len (b)-1):
if b[i] == " " and b[i+1] != " ":
word = True
result += 1
else:
word = False
return result
if __name__ == "__main__":
count (a, b)
terminal command:
python counting.py count "hello world" "let's check you out"
useing sys model,
add this code, the sys.argv first parameter is this file name
import sys
if __name__ == "__main__":
a = sys.argv[1]
b = sys.argv[2]
count(a,b)
terminal command:
python counting.py "hello word" "let's check you out"
ex:
import sys
def count(s1, s2):
print s1 + s2
print sys.argv
count(sys.argv[1], sys.argv[2])
out:
python zzzzzzz.py "hello" "word"
['zzzzzzz.py', 'hello', 'word']
helloword
a and b are the arguments of count. You cannot use them outside that scope. You could instead use sys.argv to access the commandline arguments:
from sys import argv
if __name__ == "__main__":
print(count (argv[1], argv[2]))
As suggested by others using sys:
from sys import argv
def count(a, b):
return len(a.split(" ")) + len(b.split(" "))
if __name__ == "__main__":
a = argv[1]
b = argv[2]
word_count = count(a, b)
print(word_count)
Or, you could use the built-in module argparse. In case you ever have a more complex script taking arguments from the console.
import argparse
def count(a, b):
return len(a.split(" ")) + len(b.split(" "))
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Word Count")
parser.add_argument("-a", type=str, help="First Sentence")
parser.add_argument("-b", type=str, help="Second Sentence")
args = parser.parse_args()
word_count = count(args.a, args.b)
print(word_count)
Execute your script with python counting.py -a "hello world" -b "let's check you out".
And if you execute python counting.py -h, you'll get a nicely formatted help for the users:
usage: counting.py [-h] [-a A] [-b B]
Word Count
optional arguments:
-h, --help show this help message and exit
-a A First Sentence
-b B Second Sentence

Python commandline parameter not raising error if argument is wrongly used

I have the following Python code that has 1 command line optional parameter (c) that has an argument and 2 options (a and b) that do not have an argument:
import sys, getopt
def main(argv):
inputfile = ''
outputfile = ''
try:
opts, args = getopt.getopt(argv,"abc:",["csvfile="])
except getopt.GetoptError:
print 'Error in usage - a does not require an argument'
sys.exit(2)
for opt, arg in opts:
print "Raw input is: {}" .format(opt)
if opt in ("-c", "--csvfile"):
outputfile = arg
print 'Output file is {}' .format(outputfile)
elif opt == '-a':
print 'Alpha'
elif opt == '-b':
print 'Beta'
print 'User choice is {}' .format(opt.lstrip('-'))
if __name__ == "__main__":
main(sys.argv[1:])
When I enter python readwritestore.py -a I get:
Raw input is: -a
Alpha
User choice is a
This is what I was hoping for if the commandline argument is -a. However, if I enter python readwritestore.py -a csvfile_name, then I get:
Raw input is: -a
Alpha
User choice is a
This is not what I intended for. In this function, c is the only option that rquires an argument. If I enter a with an argument,
the code should give the error message that I set up
Error in usage - a does not require an argument
This does not happen for a or b. It is allowing the argument to be entered without raising an error.
If the options that do not require an argument are entered with an argument, then I would like it to raise an error. python readwritestore.py -a text
and python readwritestore.py -b text should raise the error Error in usage - a does not require an argument.
Is there a way to specify this? Is getopt() the correct way to do this?
Additional Information:
I only want python readwritestore.py -c text to work with the argument. For the other 2 options, a and b, the code should raise the error.
checking the size of sys.argv (the list of argument supplied when calling the script) can help you checking that :
import sys
import getopt
def main(argv):
inputfile = ''
outputfile = ''
opts, args = getopt.getopt(argv, "abc:", ["csvfile="])
for opt, arg in opts:
print "Raw input is:", opt
if opt in ("-c", "--csvfile"):
outputfile = arg
print 'Output file is ', outputfile
elif opt == '-a':
if len(sys.argv)=2:
print 'Alpha'
else:
print "incorect number of argument"
elif opt == '-b':
if len(sys.argv)=2:
print 'Beta'
else:
print "incorect number of argument"
print 'User choice is ', opt
if __name__ == "__main__":
main(sys.argv[1:])
I know it's not what you asked (argparse) but here is how you could do it with argparse :
from argparse import *
def main():
parser = ArgumentParser()
parser.add_argument('-c', '--csvfile', help='do smth with cvsfile')
parser.add_argument(
'-a', '--Alpha', help='Alpha', action='store_true')
parser.add_argument(
'-b', '--Beta', help='beta smth', action='store_true')
if args.csvfile:
print 'Output file is {}' .format(args.csvfile)
if args.Alpha:
print 'Alpha'
if args.Beta:
print 'Beta'
if __name__ == "__main__":
main()
It will raise an error is to many argument are supplied. (also python readwritestore.py -h will display the help just like man in unix)

Python Regex Syntax

I have the following function:
def handleRequest(self, command, ident, ip, duration=0):
if not re.match("^[0-9]+$", ident) or not re.match("^[0-9.]+$", ip) or \
(duration and not re.match("^[0-9]+$", duration)):
print ("Unknown command")
return
if command == "DOTHIS":
reactor.callInThread(self.func, ident, "./DOTHIS.sh", ip, 0, command)
elif command == "DOTHAT":
reactor.callInThread(self.func, ident, "./DOTHAT.sh", ip, 0, command)
elif command == "DOTHAT":
reactor.callInThread(self.func, ident, "./DOTHING.sh", ip, duration, command)
elif command == "DOMORETHINGS":
reactor.callInThread(self.func, ident, "./DOMORETHINGS.sh", ip, duration, command)
else:
print ("Unknown command")
return
I use this function to execute certain scripts on my server.
My problem is the correct syntaxis of the to be executed commands (DOTHIS, DOTHAT etc.)
It must have something to do with regex.
The commands can have several parameters (e.g. DOTHIS 127.0.0.1).
No matter how I query the command, the result is always "Unknown Command".
Could anyone give me an example of a command with the right syntaxis (including a couple of parameters).
Thanks!
in handleRequest what are you sample inputs ?
i.e for command, ident?
assuming ip='127.0.0.1', duration ='10'
FYI, This condition always make the output False if the string contains just number.
(duration and not re.match("^[0-9]+$", duration))
This assumes all arguments are strings, but this should work:
import re
def handleRequest(self, command, ident, ip, duration=0):
returnEarly = 0
if not re.match("^\d+$", ident):
print ("Invalid ident")
returnEarly = 1
if not re.match("^[\d.]+$", ip):
print ("Invalid ip")
returnEarly = 1
if (duration and not re.match("^\d+$", duration)):
print ("Invalid Duration")
returnEarly = 1
if returnEarly:
return
if command == "DOTHIS":
print ("DOTHIS")
elif command == "DOTHAT":
print ("DOTHAT")
elif command == "DOTHING":
print ("DOTHING")
elif command == "DOMORETHINGS":
print ("DOMORETHING")
else:
print ("Unknown command")
handleRequest("", "DOTHIS", "11", "127.0.0.1", "10") # works
handleRequest("", "BADCOMMAND", "11", "127.0.0.1", "10") # fails on command
handleRequest("", "DOTHIS", "11C", "127.0.0B.1", "A10") # fails on arguments
I used the "\d" regex shortcut in python for numbers, I also made each check explicit so if it does fail you know why. If you are passing in arguments that are not strings you can use str(argX) to convert it to a string before checking. I used python 2.7 to test this.
EDIT:
I should also point out, that I lazily did not make this method part of a class, and just passed in the empty string for self.
re.match("^[0-9.]+$", number)
matches all strings that contain only numbers.
So you should be able to do:
def handleRequest(self, command = '0', ident = '0', ip = '0', duration='0'):
use help('re') to find out about what the characters mean.

Variables not saved using getopt for command line options (python)

I am trying to create a program in python and my biggest problem is getting it to use command line options to assign the variables in the program. I have been using getopt and it will print from where I define it, but the variables can not be called upon outside of the definition so that I can use for the rest of my program.
In the code below, the print state for the "Is the following correct" comes out fine but if I try to print the gender or any other variable after the code, I just get an error that it isn't defined.
By the way, the options I run are: spice.py -g m -n 012.345.6789 -r 23 -e 13 -o voicemail.mp3
Code:
import sys
import getopt
def main(argv):
gender = 'missing'
phone = 'missing'
reasons = 'missing'
endings = 'missing'
output = 'missing'
try:
opts, args = getopt.getopt(argv, "hg:n:r:e:o:")
except getopt.GetoptError:
print 'spice.py -g <gender> -n <phone number> -r <reasons> -e <endings> -o <output name>'
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
print 'test.py -i <inputfile> -o <outputfile>'
sys.exit()
elif opt in ("-g"):
gender = arg
elif opt in ("-n"):
phone = arg
elif opt in ("-r"):
reasons = arg
elif opt in ("-e"):
endings = arg
elif opt in ("-o"):
output = arg
print "Is the following correct? " + "Gender: " + gender + ", " + "Phone Number: " + phone + ", " + "Reasons: " + reasons + ", " + "Endings: " + endings + ", " + "Output: " + output
if __name__ == "__main__":
main(sys.argv[1:])
print gender
in your code, gender is not global. it's only in context within the function.
as proof, change the first couple of lines to:
import sys
import getopt
gender = 'missing'
def main(argv):
global gender
# ... all the same
# ... below here
and you'll now see that it prints (assuming it was working in context as you describe).
when you refactor you'll actually want to either write functions that return the values you want to use and then use them or create global variables and clean up the code a bit.

Categories

Resources