Closing a connection with a `with` statement
<p>I want to have a class that represents an IMAP connection and use it with a <code>with</code> statement as follows:</p>

<pre><code>class IMAPConnection:
    def __enter__(self):
        connection = imaplib.IMAP4_SSL(IMAP_HOST)

        try:
            connection.login(MAIL_USERNAME, MAIL_PASS)
        except imaplib.IMAP4.error:
            log.error('Failed to log in')

        return connection

    def __exit__(self, type, value, traceback):
        self.close()

with IMAPConnection() as c:
    rv, data = c.list()
    print(rv, data)
</code></pre>

<p>Naturally this fails since <code>IMAPConnections</code> has no attribute <code>close</code>. How can I store the connection and pass it to the <code>__exit__</code> function when the <code>with</code> statement is finished?</p>

<p>You need to store connection in object attributes. Something like this: </p>

<pre><code>class IMAPConnection:
    def __enter__(self):
        self.connection = imaplib.IMAP4_SSL(IMAP_HOST)

        try:
            self.connection.login(MAIL_USERNAME, MAIL_PASS)
        except imaplib.IMAP4.error:
            log.error('Failed to log in')

        return self.connection

    def __exit__(self, type, value, traceback):
        self.connection.close()
</code></pre>

<p>You would also want to implement <code>list</code> method for you class.</p>

<p>Edit: I just now realized what your actual problem is. when you do <code>with SomeClass(*args, **kwargs) as c</code> <code>c</code> is not a value returned by <code>__enter__</code> method. <code>c</code> is instance of <code>SomeClass</code>. That's a root of your problem you returned connection from <code>__enter__</code> and assumed that <code>c</code> is said connection. </p>

python imap with-statement imaplib