How can I prevent or trap StopIteration exception in the yield-calling function?
You can trap the StopIteration
exception in the lexical scope of the buggy
function this way:
import csv # essential!
def buggy(csvfile):
with open(csvfile) as stream:
reader = csv.reader(stream)
try:
yield next(reader)
except StopIteration:
yield 'dummy value'
for row in reader:
yield row
You basically manually request the first value from the reader
iterator and
- if this succeeds, the first line is read from the csv file and is yielded to the caller of
buggy
function - if this fails, as is the case for empty csv files, some string e.g.
dummy value
is yielded to prevent the caller of thebuggy
function from crashing
Afterwards, if the csv file was not empty, the remaining rows will be read (and yielded) in the for cycle.
EDIT: to illustrate why the other variation of mymod.py
mentioned in the question does not work, I've added some print statements to it:
import csv # essential!
def buggy(csvfile):
with open(csvfile) as stream:
reader = csv.reader(stream)
try:
print('reading first row')
firstrow = next(reader)
except StopIteration:
print('no first row exists')
firstrow = None
if firstrow != None:
print('yielding first row: ' + firstrow)
yield firstrow
for row in reader:
print('yielding next row: ' + row)
yield row
print('exiting function open')
Running it gives the following output:
% ./myscript.py empty_input.csv first
reading first row
no first row exists
exiting function open
Traceback (most recent call last):
File "myscript.py", line 15, in <module>
main(*sys.argv[1:])
File "myscript.py", line 9, in main
print_row(next(mymod.buggy(csvfile)))
That shows, that in case that the input file is empty, the first try..except
block correctly handles the StopIteration
exception and that the buggy
function continues on normally.
The exception that the caller of the buggy
gets in this case is due to the fact that the buggy
function does not yield any value before completing.