Python: reading filename from command line argument - python

I am making a simple script that counts some values from a csv file generated from google forms.
The script is as follows:
import csv
import os.path
fileName=None
if __name__=="__main__":
try:
fileName=argv[1]
isFile(fileName)
pass
except Exception as e:
print("You must provide a valid filename as parameter")
raise
def isFile(fileName):
if(not os.path.isfile(fileName)):
raise ValueError("You must provide a valid filename as parameter")
print fileName
def readCsvAndCountPercentPerFormItemFromGoogleForms(fileName):
times={}
totalRows=0
with open(fileName,'r') as csvfile:
csvReader=csv.reader(csvfile);
for row in csvreader:
value=row[1]
if(value in times.values()):
times[value]+=1
else:
times[value]=1
totalRows+=1
return calculateDictionaryAsPercent(times,totalRows)
def calculateDictionaryAsPercent(times,totalRows):
if(totalRows==0):
raise ValueError("The file does not contain any rows")
for key,val in times.items():
times[key]=(val/totalRows)*100
return times
finalTimes=readCsvAndCountPercentPerFormItemFromGoogleForms(fileName)
print finalTimes
But I get the following error:
Traceback (most recent call last):
File "csv.py", line 1, in <module>
import csv
File "/home/pcmagas/Kwdikas/python/csv.py", line 54, in <module>
finalTimes=readCsvAndCountPercentPerFormItemFromGoogleForms(fileName)
File "/home/pcmagas/Kwdikas/python/csv.py", line 26, in readCsvAndCountPercentPerFormItemFromGoogleForms
with open(fileName,'r') as csvfile:
TypeError: coercing to Unicode: need string or buffer, NoneType found
The problem is that for some reason the variable fileName does not change value in:
if __name__=="__main__":
try:
fileName=argv[1]
isFile(fileName)
pass
except Exception as e:
print("You must provide a valid filename as parameter")
raise
The following piece of code was base ton the first answer found on Detect and print if no command line argument is provided
So can you offer me a solution because I do not write python too often, therefore I did the following script in order to learn it better.
Edit 1
The code has been reformated to this:
import csv
from sys import argv
import os.path
def isFile(fileName):
if(not os.path.isfile(fileName)):
raise ValueError("You must provide a valid filename as parameter")
def readCsvAndCountPercentPerFormItemFromGoogleForms(fileName):
times={}
totalRows=0
with open(fileName,'r') as csvfile:
csvReader=csv.reader(csvfile);
for row in csvreader:
value=row[1]
if(value in times.values()):
times[value]+=1
else:
times[value]=1
totalRows+=1
return calculateDictionaryAsPercent(times,totalRows)
def calculateDictionaryAsPercent(times,totalRows):
if(totalRows==0):
raise ValueError("The file does not contain any rows")
for key,val in times.items():
times[key]=(val/totalRows)*100
return times
fileName=None
if __name__=="__main__":
try:
fileName=argv[1]
print("Filename: ",fileName)
isFile(fileName)
pass
except Exception as e:
print("You must provide a valid filename as parameter")
raise
print("Filename: ",fileName)
finalTimes=readCsvAndCountPercentPerFormItemFromGoogleForms(fileName)
print finalTimes
Still the same error.

In the end as mentioned the script should be this one:
import csv
from sys import argv
import os.path
def readCsvAndCountPercentPerFormItemFromGoogleForms(fileName):
times={}
totalRows=0
with open(fileName,'r') as csvfile:
csvReader=csv.reader(csvfile);
for row in csvReader:
value=row[1]
if(value in times.values()):
times[value]+=1
else:
times[value]=1
totalRows+=1
return calculateDictionaryAsPercent(times,totalRows)
def calculateDictionaryAsPercent(times,totalRows):
if(totalRows==0):
raise ValueError("The file does not contain any rows")
for key,val in times.items():
times[key]=(val/totalRows)*100
return times
def isFile(fileName):
if(not os.path.isfile(fileName)):
raise ValueError("You must provide a valid filename as parameter")
fileName=None
if __name__=="__main__":
try:
fileName=argv[1]
isFile(fileName)
pass
except Exception as e:
print("You must provide a valid filename as parameter")
raise
finalTimes=readCsvAndCountPercentPerFormItemFromGoogleForms(fileName)
print finalTimes

Related

How to split input arguments in Python

I have the below code which expects 1 or more file names as arguments.
It works for one file but now the input arguments can be multiple files such as 1.json 2.json 3.json.
How can I handle this?
import sys
import os
import json
inFile = sys.argv[1]
print(inFile)
with open(inFile, 'r') as file:
try:
json_data = json.load(file)
except ValueError as e:
print "Invalid Json supplied:%s" % e
exit(1)
else:
print "json file ok"
print(json_data)
Since argv is a list (parsing the passed arg string is done for you), you can iterate over it, skipping argv[0] which is the program filename:
import json
import sys
for arg in sys.argv[1:]:
with open(arg, "r") as file:
try:
json_data = json.load(file)
print "json file ok"
print json_data
except ValueError as e:
print "Invalid JSON supplied: %s" % e
exit(1)
You may want to put this data into a list so you can do something with it in your program:
import json
import sys
data = []
for arg in sys.argv[1:]:
with open(arg, "r") as file:
try:
data.append(json.load(file))
except ValueError as e:
print "Invalid JSON supplied: %s" % e
exit(1)

Error/Exception with parameters

I would like to know how I can throw exceptions / errors to say that a parameter is null or its not in the .txt file that works as a dictionnary.
The dictionnary it's like that:
"""rule:parameter:value"""
aa:alfa:1
bba:beta:15
I got this for the moment:
def get(rule_name,parameter_name):
try:
with open("parameters.txt", "r") as infile:
for line in infile:
if line.startswith(rule_name.lower()) and line.split(":")[1] == parameter_name.lower():
return line.split(":")[2]
except Value:
print "Error"
if __name__=="__main__":
print(get("aa","alfa")) #return the value associated to the rule and the parameter
Just raise a value error
raise ValueError("you parameter is null or in wrong format")

Cannot stop program from crashing with wrong file entered by user

I am creating a program which asks the user to choose a file to run within the program but I can't stop the program from crashing when a file name that does not exist is entered. I have tried try statements and for loops but they have all given an error. The code I have for choosing the file is below:
data = []
print "Welcome to the program!"
chosen = raw_input("Please choose a file name to use with the program:")
for line in open(chosen):
our_data = line.split(",")
data.append(our_data)
Add an exception:
data = []
print "Welcome to the program!"
chosen = raw_input("Please choose a file name to use with the program:")
try:
for line in open(chosen):
our_data = line.split(",")
data.append(our_data)
except IOError:
print('File does not exist!')
Without using an exception you can simply check if the file exists and if not ask for it again.
import os.path
data = []
print "Welcome to the program!"
chosen='not-a-file'
while not os.path.isfile(chosen):
if chosen != 'not-a-file':
print("File does not exist!")
chosen = raw_input("Please choose a file name to use with the program:")
for line in open(chosen):
our_data = line.split(",")
data.append(our_data)
RTM
import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except IOError as e:
print "I/O error({0}): {1}".format(e.errno, e.strerror)
except ValueError:
print "Could not convert data to an integer."
except:
print "Unexpected error:", sys.exc_info()[0]
raise

How does this work: except IOError as e: print("No such file: {0.filename}".format(e))

The code that uses the expression in question:
def read_file(self,file_name):
try:
with open(file_name,'r') as file:
data=file.read()
return data.split()
except IOError as e:
print("Could not read file:{0.filename}".format(e))
sys.exit()
How does this work? What is meaning of {0.filename}.format(e)? Why do we use {0.filename} and not {1.filename}?
This essentially means takes the positional argument at position 0 (in format(e), e is the zero position arg) and grab the filename attribute defined on it:
print("No such file: {0.filename}".format(e))
Is similar to:
print("No such file: {0}".format(e.filename))
It isn't 1.filename because format hasn't been called with an argument at position 1, another example might help you out even more:
print("{0}{1.filename}".format("No such File: ", e))
Here {0} will grab "No such File: " and {1.filename} will grab e.filename and add it to the resulting string.

Best way to read file contents of a file and set to empty string if exception happen

try:
content = open("/tmp/out").read()
except:
content = ""
Can I go any shorter or more elegant than this? I've to do it for more than one files so I want something more short.
Is writing function the only shorter way to do it?
What I actually want is this but I want to concat "" if there is any exception
lines = (open("/var/log/log.1").read() + open("/var/log/log").read()).split("\n")
Yes, you'll have to write something like
def get_contents(filename):
try:
with open(filename) as f:
return f.read()
except EnvironmentError:
return ''
lines = (get_contents('/var/log/log.1')
+ get_contents('/var/log/log')).split('\n')
NlightNFotis raises a valid point, if the files are big, you don't want to do this. Maybe you'd write a line generator that accepts a list of filenames:
def get_lines(filenames):
for fname in filenames:
try:
with open(fname) as f:
for line in f:
yield line
except EnvironmentError:
continue
...
for line in get_lines(["/var/log/log.1", "/var/log/log"]):
do_stuff(line)
Another way is to use the standard fileinput.FileInput class (thanks, J.F. Sebastian):
import fileinput
def eat_errors(f, mode):
try:
return open(f, mode)
except IOError:
return open(os.devnull)
for line in fileinput.FileInput(["/var/log/log.1", "/var/log/log"], openhook=eat_errors):
do_stuff(line)
This code will monkey patch out open for another open that creates a FakeFile that always returns a "empty" string if open throws an `IOException``.
Whilst it's more code than you'd really want to write for the problem at hand, it does mean that you have a reusable context manager for faking open if the need arises again (probably twice in the next decade)
with monkey_patched_open():
...
Actual code.
#!/usr/bin/env python
from contextlib import contextmanager
from StringIO import StringIO
################################################################################
class FakeFile(StringIO):
def __init__(self):
StringIO.__init__(self)
self.count = 0
def read(self, n=-1):
return "<empty#1>"
def readlines(self, sizehint = 0):
return ["<empty#2>"]
def next(self):
if self.count == 0:
self.count += 1
return "<empty#3>"
else:
raise StopIteration
################################################################################
#contextmanager
def monkey_patched_open():
global open
old_open = open
def new_fake_open(filename, mode="r"):
try:
fh = old_open(filename, mode)
except IOError:
fh = FakeFile()
return fh
open = new_fake_open
try:
yield
finally:
open = old_open
################################################################################
with monkey_patched_open():
for line in open("NOSUCHFILE"):
print "NOSUCHFILE->", line
print "Other", open("MISSING").read()
print "OK", open(__file__).read()[:30]
Running the above gives:
NOSUCHFILE-> <empty#3>
Other <empty#1>
OK #!/usr/bin/env python
from co
I left in the "empty" strings just to show what was happening.
StringIO would have sufficed just to read it once but I thought the OP was looking to keep reading from file, hence the need for FakeFile - unless someone knows of a better mechanism.
I know some see monkey patching as the act of a scoundrel.
You could try the following, but it's probably not the best:
import os
def chk_file(filename):
if os.stat(filename).st_size == 0:
return ""
else:
with open(filename) as f:
return f.readlines()
if __name__=="__main__":
print chk_file("foobar.txt") #populated file
print chk_file("bar.txt") #empty file
print chk_file("spock.txt") #populated
It works. You can wrap it with your try-except, if you want.
You could define a function to catch errors:
from itertools import chain
def readlines(filename):
try:
with open(filename) as file:
return file.readlines() # or just `file` to return an iterator
except EnvironmentError:
return []
files = (readlines(name) for name in ["/var/log/1", "/var/log/2"])
lines = list(chain.from_iterable(files))

Categories

Resources