python - Exception while handling generator.send() in try...except block

filename = 'tempfile'

def tail(filename):
    fd = open(filename)
    while True:
        line = fd.readline()
        if not line:
            continue
        else:
            if filename != 'uh':
                yield line
            else:
                print 'Returning f to close the file'
                yield fd


try:
    genObj = tail(filename) 
    valfromgen= genObj.next()
    while valfromgen:
        print valfromgen
        valfromgen= genObj.next()
except:
    traceback.print_exc()
    try:
        fd_Got_Back = genObj.send('uh')
        fd_Got_Back.close()
    except:
        traceback.print_exc()

Intention of the code: I have opened the file in the generator function only and not outside it, but, I want to close that file outside the generator function by using 'send' probably.

What I am trying to do: Replicating tail -f from unix.

How I am trying to do:

  1. Open a tempfile in read mode.
  2. If the tempfile has 1 new line written in it (which I'll keep on writing manually and saving tempfile using notepad), yield the newly written line.

Problem:

The problem is that I'm trying to check how I can close the opened tempfile from this python code if I press Ctrl + C (i.e. SIGTERM) when this Python code runs in command prompt. In order to emulate this, I have opened the tempfile in the tail function, and whenever there is an exception (which will be raised by the system when I press Ctrl + C), the control should go in the 1st except. Then, from here, I'm trying to send a value uh to the generator function tail, so that it should yield the file descriptor of the opened file which I can use to close the opened tempfile.

PS: I expect a solution where I have opened the file in the generator function only and not outside it.

2 Answers

  1. Leonard- Reply

    2019-11-15

    I think You're misunderstanding how "send" works. Send simply causes a generator to yield that value on its next iteration. It does not change the value of the original parameters. You can then use that yielded value for some purpose. So you could make your code:

    filename = 'tempfile'
    
    def tail(filename):
        fd = open(filename)
        while True:
            line = fd.readline()
            if not line:
                continue
            else:
                x = (yield line)
                if (x == 'uh'):
                    print 'Returning f to close the file'
                    yield fd
    
    
    try:
        genObj = tail(filename) 
        valfromgen= genObj.next()
        while valfromgen:
            print valfromgen
            valfromgen= genObj.next()
    except:
        traceback.print_exc()
        try:
            genObj.send('uh').close()
        except:
            traceback.print_exc()
    
  2. Leopold- Reply

    2019-11-15

    I have figured out the problem where I was stuck and I have come up with this solution:-

    1. When I press Ctrl + C (on Windows), the KeyboardInterrupt actually happens in fd.readline(). So, I just placed a try...except there, so that the generator function yields the file descriptor whenever Ctrl + C is hit. If there is no KeyBoardInterrupt , then, just print a newly read line from tempfile
    2. This file descriptor is checked using isinstance() in the main body, and if it is found to be a file, then, I'm closing the file as well as the generator

    PS: (this KeyboardInterrupt might vary on Linux..probably SigTerm will be raised, but, please check. So, in order to make the code generic, just remove KeyBoard Interrupt and use just normal except)

    import sys,  traceback
    
    filename = 'tempfile'
    
    def tail(filename):
        fd = open(filename)
        while True:
            try:
                line = fd.readline()
            except KeyboardInterrupt:
                print 'keyboard interrupt here'
                yield fd
            if not line:
                continue
            else:
                yield line
    
    
    try:
        genObj = tail(filename) 
        valfromgen= genObj.next()
        while valfromgen:       
            if isinstance(valfromgen, file):
                print 'Closing this file now as `tail` yielded a file descriptor'
                valfromgen.close()
                genObj.close()
                break
            print 'Yielded line: ', valfromgen
            valfromgen= genObj.next()
    
        print 'Just in order to check that things are in order, the following line will raise StopIteration. If it raises, it means we are good.'
        print genObj.next()
    except:
        traceback.print_exc()
    

Leave a Reply

Your email address will not be published. Required fields are marked *

You can use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>