1 Comment

  1. I recently had to loop over the messages in a BUFR file and I found the wiki examples very clear but not hugely Pythonic. Instead of something like...
    F=open('somefile.bufr','r')
    while True:
        gid=codes_bufr_new_from_file(F)
        if gid is None:
            break
        ... process message gid ...
    F.close()
    ... which isn't exception-safe, what I wanted to write was something like...
    for gid in bufr_messages('somefile.bufr'):
       ... process message gid ...
    and have bufr_messages() take care of all the opening and closing of the file and getting and releasing of the messages in an exception-safe way, so I wrote this...
    from eccodes import codes_bufr_new_from_file, codes_release
     
    ###########################################################################
    def bufr_messages(filename):
    ###########################################################################
        """Generator function allowing iteration over all messages in a BUFR
           file. Exception-safe."""
     
        with open(filename,'r') as F:
            while True:
                with NextBufrMessage(F) as gid:
                    yield gid
     
    ###########################################################################
    class NextBufrMessage(object):
    ###########################################################################
        """Context manager class for a BUFR message. Automatically calls
           codes_release() on the message even if an exception is raised while
           processing it. Raises a StopIteration exception if there are no more
           messages in the file."""
     
        def __init__(self,F):
            # Store the bufr file descriptor on entering the context
            self.F=F
     
        def __enter__(self):
            # Read, store and return the next message
            self.gid=codes_bufr_new_from_file(self.F)
            if self.gid is None:
                raise StopIteration
            return self.gid
     
        def __exit__(self,ex_type,ex_value,ex_trace):
            # Clean up the message when leaving the context or on exception
            codes_release(self.gid)
     

    So now if I write...

    for gid in bufr_messages('somefile.bufr'):

    ... I know that if an exception occurs during processing of the message the message will be automatically released and the file automatically closed.