1
\$\begingroup\$

I'm writing a script to archive email messages from one IMAP folder to another. It looks, more or less, like the following. I've obfuscated about 30 lines unrelated to this question:

import imaplib
import getpass

def main():
    user = getpass.getuser() + '@mymailbox.com'
    mailbox = imaplib.IMAP4_SSL('mymailbox.com', 993)
    try:
        mailbox.login(user, getpass.getpass())
    except imaplib.IMAP4.error:
        raise RuntimeError('Credential error.')
    mailbox.select('my_mailbox')

    # Here lies some 30 lines not relevant to the question, but which
    # find mailbox messages, copies them to another folder, and
    # sets the delete flag in 'my_mailbox'.

    try:
        mailbox.close()    # which also expunges the mailbox
    except:
        pass
    mailbox.logout()

After working with my IMAP server for a while, I've discovered a fair amount of unexpected error conditions arising from its implementation of RFC 3501. No matter what, however, I always want to attempt mailbox.close() and mailbox.logout().

It sounds like a good occasion for a try / finally block, and that usage is supported by other examples. All the same, it feels unnatural to wrap some 40 lines of main() execution in a try-block:

def main():
    user = getpass.getuser() + '@mymailbox.com'
    mailbox = imaplib.IMAP4_SSL('mymailbox.com', 993)
    try:
        try:
            mailbox.login(user, getpass.getpass())
        except imaplib.IMAP4.error:
            raise RuntimeError('Credential error.')
        mailbox.select('my_mailbox')

        # Here lies some 30 lines not relevant to the question, but which
        # find mailbox messages, copy them to another folder, and
        # set delete flags in 'my_mailbox'.
    finally:
        try:
            mailbox.close()    # which also expunges the mailbox
        except:
            pass
        mailbox.logout()

Is that a common pattern? I could also write my own context manager; perhaps that's the better way to go. What's the best practice for long-running connections like this?

\$\endgroup\$
2
\$\begingroup\$

Move the working logic into its own function

def process_mailbox(mailbox):
    user = getpass.getuser() + '@mymailbox.com'
    try:
        mailbox.login(user, getpass.getpass())
    except imaplib.IMAP4.error:
        raise RuntimeError('Credential error.')
    mailbox.select('my_mailbox')
    #whatever else

def main():
    mailbox = imaplib.IMAP4_SSL('mymailbox.com', 993)
    try:
        process_mailbox(mailbox)
    finally:
        try:
            mailbox.close()    # which also expunges the mailbox
        except:
            pass
        mailbox.logout()
\$\endgroup\$
  • \$\begingroup\$ Stunningly obvious, in retrospect. Any thoughts on with vs. try / finally here? \$\endgroup\$ – Christopher May 6 '13 at 2:49
  • \$\begingroup\$ @Christopher, the with gets really helpful if you need to do this a lot. If this is the only function where you do it, it wouldn't seem all that people. \$\endgroup\$ – Winston Ewert May 6 '13 at 2:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.