Python Command Line Arguments Try/Except - python

I want to create a program that will take two command line arguments. The first being the name of a file to open for parsing and the second the flag -s. If the user provides the wrong number of arguments or the other argument is not -s then it will print the message "Usage: [-s] file_name" and terminate the program using exit.
Next, I want my program to attempt to open the file for reading. The program should open the file read each line and return a count of every float, integer, and other kinds of strings that are not ints or floats. However, if opening the file fails it should raise an exception and print "Unable to open [filename]" and quit using exit.
I've been looking up lots of stuff on the internet about command lines in Python but I've ended up more confused. So here's my attempt at it so far from what I've researched.
from optparse import OptionParser
def command_line():
parser = OptionParser()
parser.add_option("--file", "-s")
options, args = parser.parse_args()
if options.a and obtions.b:
parser.error("Usage: [-s] file_name")
exit
def read_file():
#Try:
#Open input file
#Except:
#print "Unable to open [filename]"
#Exit

from optparse import OptionParser
import sys,os
def command_line():
parser = OptionParser("%prog [-s] file_name")
parser.add_option("-s",dest="filename",
metavar="file_name",help="my help message")
options, args = parser.parse_args()
if not options.filename:
parser.print_help()
sys.exit()
return options.filename
def read_file(fn):
if os.path.isfile(fn):
typecount = {}
with open(fn) as f:
for line in f:
for i in line.split()
try:
t = type(eval(i))
except NameError:
t = type(i)
if t in typecount:
typecount[t] += 1
else:
typecount[t] = 1
else:
print( "Unable to open {}".format(fn))
sys.exit()
print(typecount)
read_file(command_line())
So step by step:
options.a is not defined unless you define an option --a or (preferably) set dest="a".
using the built-in parser.print_help() is better than making your own, you get -h/--help for free then.
you never called your function command_line, therefore never getting any errors, as the syntax was correct. I set the commandline to pass only the filename as a return value, but there are better ways of doing this for when you have more options/arguments.
When it comes to read_file, instead of using try-except for the file I recommend using os.path.isfile which will check whether the file exists. This does not check that the file has the right format though.
We then create a dictionary of types, then loop over all lines and evaluate objects which are separated by whitespace(space,newline,tab). If your values are separated by eg. a comma, you need to use line.split(',').
If you want to use the counts later in your script, you might want to return typecount instead of printing it.

Related

How to print file path and line number while program execution?

I am running a Python program and I am getting an error. The program is written by someone.
The program has a lot of classes, methods, loops etc.,
Assume that I got an error, the error reporting in Python contains the line number and the nested call information and ends with key error.
I want something like this:
While the program executes, the output, which I can see in terminal, should contain the filename (or path of the file) and the line number it is executing and the error reporting should be as usual.
Example (output):
file1 line1: normal output (if any)
file1 line2: normal output (if any)
file2 line1: normal output (if any)
file2 line2: normal output (if any)
file1 line9: normal output (if any)
file1 line10: normal output (if any)
.......................................
You just need to set up a log format of your choice that consists of lineno and pathname. Consider this file called test.py:
import logging
logging.basicConfig(
format="%(pathname)s line%(lineno)s: %(message)s",
level=logging.INFO
)
logging.info("test message")
And when you run this program,
$ python3 test.py
test.py line6: test message
Just paste the above snippet in any of your files. Make sure it is executed before any calls to any logging calls.
Here's a list of all parameters you can use in logging formats: logging.LogRecord
Use two internal modules of Python (linecache, sys) :
import linecache
import sys
def PrintException():
exc_type, exc_obj, exc_info = sys.exc_info()
f = exc_info.tb_frame
lineno = exc_info.tb_lineno
filename = f.f_code.co_filename
linecache.checkcache(filename)
line = linecache.getline(filename, lineno, f.f_globals)
print ('{}, {} "{}" (Error: {})'.format(filename, lineno, line.strip(), exc_obj))
try:
print (1/0) # place here code which you need check
except:
PrintException()

Python getopts issue

import pywaves as pw
import sys, getopt
amount = 0
receive = ''
try:
options, remainder = getopt.getopt(
sys.argv[1:],
'r:a',
['receive',
'amount',
])
except getopt.GetoptError as err:
print('ERROR:', err)
sys.exit(1)
for opt, arg in options:
if opt in ('-a', '--amount'):
amount = arg
elif opt in ('-r', '--receive'):
receive = arg
print('OPTIONS :', options)
myAddress = pw.Address(privateKey='MYPRIVATEKEY')
otherAddress = pw.Address(receive)
myToken = pw.Asset('MYADDRESS')
myAmount = amount
myAddress.sendAsset(otherAddress, myToken, myAmount)
I tried run the code above and it seems my option "a" was not captured. What should I do to get it working?
I run the following command line
python this.py -r 3PFPovgPu3aBWA1krU544tPDTFiHgpvu7q1 -a 150
It returns
('OPTIONS :', [('-r', '3PFPovgPu3aBWA1krU544tPDTFiHgpvu7q1'), ('-a', '')])
I not sure why the "a" value was empty. How do I change my code to make it work properly?
You need to add a colon after the second parameter 'a'. So try
getopt.getopt(sys.argv[1:],'r:a:',['receive','amount'])
See the documentation for getopt, there it is said clearly:
Parses command line options and parameter list. args is the argument list to be parsed, without the leading reference to the running program. Typically, this means sys.argv[1:]. options is the string of option letters that the script wants to recognize, with options that require an argument followed by a colon (':'; i.e., the same format that Unix getopt() uses).

Python: Can optparse have the ACTION attribute to act both like STORE and STORE_TRUE?

I am using optparse to get command line input.
Lets say that I am running a script demo.py and it creates some output. But unless I specify the command line input, the output is not written to a file.
I am trying to do the following:
python demo.py in command line should run the script, but not write the output anywhere.
python demo.py -o in command line should write the output to my default file name output.txt.
python demo.py -o demooutput.txt in command line should write the output to file demooutput.txt.
PS: I would not prefer to switch to argparse from optparse.
You can use optparse-callbacks to achieve this.
Here is how it wiill work for your use case.
parser.add_option("-o", action="callback", dest="output", callback=my_callback)
def my_callback(option, opt, value, parser):
if len(parser.rargs) > 0:
next_arg = parser.rargs[0]
if not next_arg.startswith("-"):
# Next argument is not another option
del parser.rargs[0]
setattr(parser.values, option.dest, next_arg)
return
# If not processed, set the default value
setattr(parser.values, option.dest, "output.txt")
I don't think there is unfortunately - the only way I can think of is hacking around the problem by adding your own logic statements. The following code should do the trick.
import re, sys
import optparse from OptionParser
usage = "usage: %prog [options] arg"
parser = OptionParser(usage)
if '-f' in argv:
a = argv.index('-f')
if (a != len(argv)-1) and re.search('[.]txt', argv[a+1]):
parser.add_option("-f", "--foo", dest="foo")
else:
parser.add_option("-f", dest="foo", action="store_true")
This doesn't answer the direct question, 'how to define an Action...', but it handles the inputs in a simple way.
Set '-o' to be 'store_true'. If True check the 'args' variable for a file name.
(options, args) = parser.parse_args()
if options.o:
if args:
dest = args[0]
else:
dest = 'output.txt'
else:
dest = ''
(In argparse the equivalent would be to define a positional argument with nargs='?'.)
If these are the only arguments, you could also get by with checking for the filename without requiring the `-o'.
Another possibility - 'store_const', with the positional 'filename' having priority:
parser = optparse.OptionParser()
parser.add_option('-o',dest='dest',action='store_const', const='output.txt', default='')
(options, args) = parser.parse_args()
if args:
options.dest = args[0]
print options

How to use subprocess to execute programs with Python

Hello i am using the subprocess.Popen() class and i succesful execute commands on the terminal, but when i try to execute programs for example an script written on Python and i try to pass arguments the system fails.
This is the code:
argPath = "test1"
args = open(argPath, 'w')
if self.extract.getByAttr(self.block, 'name', 'args') != None:
args.write("<request>"+self.extract.getByAttr(self.block, 'name', 'args')[0].toxml()+"</request>")
else:
args.write('')
car = Popen(shlex.split('python3.1 /home/hidura/webapps/karinapp/Suite/ForeingCode/saveCSS.py', stdin=args, stdout=subprocess.PIPE, stderr=subprocess.PIPE))
args.close()
dataOut = car.stdout.read().decode()
log = car.stderr.read().decode()
if dataOut!='':
return dataOut.split('\n')
elif log != '':
return log.split('\n')[0]
else:
return None
And the code from the saveCSS.py
from xml.dom.minidom import parseString
import os
import sys
class savCSS:
"""This class has to save
the changes on the css file.
"""
def __init__(self, args):
document = parseString(args)
request = document.firstChild
address = request.getElementsByTagName('element')[0]
newdata = request.getElementsByTagName('element')[1]
cssfl = open("/webapps/karinapp/Suite/"+address.getAttribute('value'), 'r')
cssData = cssfl.read()
cssfl.close()
dataCSS = ''
for child in newdata.childNodes:
if child.nodeType == 3:
dataCSS += child.nodeValue
nwcssDict = {}
for piece in dataCSS.split('}'):
nwcssDict[piece.split('{')[0]] = piece.split('{')[1]
cssDict = {}
for piece in cssData.split('}'):
cssDict[piece.split('{')[0]] = piece.split('{')[1]
for key in nwcssDict:
if key in cssDict == True:
del cssDict[key]
cssDict[key] = nwcssDict[key]
result = ''
for key in cssDict:
result += key+"{"+cssDict[key]+"}"
cssfl = open(cssfl.name, 'a')
cssfl.write(result)
cssfl.close()
if __name__ == "__main__":
savCSS(sys.stdin)
BTW: There's no output...
Thanks in advance.
OK, I'm ignoring that your code doesn't run (neither the script you try to execute, not the main script actually works), and looking at what you are doing:
It does execute the script, or you would get an error, like "bin/sh: foo: not found".
Also you seem to be using an open file as stdin after you have written to it. That doesn't work.
>>> thefile = open('/tmp/foo.txt', 'w')
>>> thefile.write("Hej!")
4
>>> thefile.read()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: not readable
You need to close the file, and reopen it as a read file. Although better in this case would be to use StringIO, I think.
To talk to the subprocess, you use communicate(), not read() on the pipes.
I'm not sure why you are using shell=True here, it doesn't seem necessary, I would remove it if I was you, it only complicates stuff unless you actually need the shell to do things.
Specifically you should not split the command into a list when using shell=True. What your code is actually doing, is starting a Python prompt.
You should rather use communicate() instead of .stdout.read().
And the code you posted isn't even correct:
Popen(shlex.split('python3.1 /home/hidura/webapps/karinapp/Suite/ForeingCode/saveCSS.py', stdin=args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
There's a missing parenthesis, and from the stdout/stderr parameters, it's clear that you get no output to the console, but rather into pipes (if that's what you meant by "There's no output...").
Your code will actually work on Windows, but on Linux you must remove the shell=True parameter. You should always omit that parameter if you provide the full command line yourself (as a sequence).

Parsing command line arguments in a python script (getopt woes)

Can anyone spot why the following script is not printing the passed arguments?
import sys, getopt
def usage():
print 'Unknown arguments'
def main(argv):
try:
opts, args = getopt.getopt(argv,'fdmse:d',['files=','data-source=','mode=','start','end'])
except getopt.GetoptError:
usage()
sys.exit(999)
for opt, arg in opts:
# print opt,arg
if opt in('-f','--files'):
print 'files: ', arg #
if __name__ == "__main__":
main(sys.argv[1:])
When I run the script at the command line and pass the arguments -f=dummy.csv, usage() seems to be invoked instead - WHY?
BTW, I find the logic of the program flow a bit weird (I copied it from here). Normally, I would have thought that the logic will be implemented in the try branch, and then AFTER that comes the exception handler.
Is this (as pasted in the code above) the 'Pythonic' way to write try/catch blocks?
Did you get your answers?
One way to debug python exceptions is to move (or copy temporarily for debugging) the code out of the try block. You'll get a full trace.
And of course another way is to reduce the test case. Here I've reduced the problems to three lines, and tried the solution hinted at by #s.lott (using 'f:' in the getopts call), and also show at the end how calling with some different test data behaves:
$ cat x1.py
import sys, getopt
opts, args = getopt.getopt(sys.argv[1:],'fdmse:d',['files=','data-source=','mode=','start','end'])
print "opts=", opts, "args=", args
$ python x1.py -f=dummy.csv argblah
Traceback (most recent call last):
File "x1.py", line 2, in <module>
opts, args = getopt.getopt(sys.argv[1:],'fdmse:d',['files=','data-source=','mode=','start','end'])
File "/usr/lib/python2.6/getopt.py", line 91, in getopt
opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:])
File "/usr/lib/python2.6/getopt.py", line 191, in do_shorts
if short_has_arg(opt, shortopts):
File "/usr/lib/python2.6/getopt.py", line 207, in short_has_arg
raise GetoptError('option -%s not recognized' % opt, opt)
getopt.GetoptError: option -= not recognized
$ sed 's/fdm/f:dm/' <x1.py >x2.py
$ diff x1.py x2.py
2c2
< opts, args = getopt.getopt(sys.argv[1:],'fdmse:d',['files=','data-source=','mode=','start','end'])
---
> opts, args = getopt.getopt(sys.argv[1:],'f:dmse:d',['files=','data-source=','mode=','start','end'])
$ python x2.py -f=dummy.csv argblah
opts= [('-f', '=dummy.csv')] args= ['argblah']
$ python x1.py -f dummy.csv argblah
opts= [('-f', '')] args= ['dummy.csv', 'argblah']
Normally, I would have thought that the logic will be implemented in the try branch
"Normally"? What does normally mean?
What is the program supposed to do? What exceptions make sense? What does the program do in response to the exceptions.
There's no "normally". Any more than there's a normal assignment statement or a normal function definition.
Your program does what makes sense to achieve the required end-state. There's no "normally".
Import and use argparse instead of getopt. It's much easier to use and has almost all you need for running from the command line, built into it.
An example,
parser = argparse.ArgumentParser(
description='Description of what the module does when run.')
parser.add_argument("-o", "--output", help='Path of log file.')
args = parser.parse_args()
As easy as that. You need to import argparse at the top of your file for this to work, of course.

Categories

Resources