Keeping context-manager object alive through function calls

Pablo Lucena plucena24 at gmail.com
Tue Nov 10 17:36:04 EST 2015


I am running into a bit of an issue with keeping a context manager open
through function calls. Here is what I mean:

There is a context-manager defined in a module which I use to open SSH
connections to network devices. The "setup" code handles opening the SSH
sessions and handling any issues, and the teardown code deals with
gracefully closing the SSH session. I normally use it as follows:

from manager import manager
def do_stuff(device):
    with manager(device) as conn:
        output = conn.send_command("show ip route")
        #process output...
    return processed_output

In order to keep the SSH session open and not have to re-establish it
across function calls, I would like to do add an argument to "do_stuff"
which can optionally return the SSH session along with the data returned
from the SSH session, as follows:

def do_stuff(device, return_handle=False):
    with manager(device) as conn:
        output = conn.send_command("show ip route")
        #process output...
        if return_handle:
            return (processed_output, conn)
        else:
            return processed_output


I would like to be able to call this function "do_stuff" from another
function, as follows, such that it signals to "do_stuff" that the SSH
handle should be returned along with the output.

def do_more_stuff(device):
    data, conn = do_stuff(device, return_handle=True)
    output = conn.send_command("show users")
    #process output...
    return processed_output

However the issue that I am running into is that the SSH session is closed,
due to the do_stuff function "returning" and triggering the teardown code
in the context-manager (which gracefully closes the SSH session).

I have tried converting "do_stuff" into a generator, such that its state is
suspended and perhaps causing the context-manager to stay open:

def do_stuff(device, return_handle=False):
    with manager(device) as conn:
        output = conn.send_command("show ip route")
        #process output...
        if return_handle:
            yield (processed_output, conn)
        else:
            yield processed_output

And calling it as such:

def do_more_stuff(device):
    gen = do_stuff(device, return_handle=True)
    data, conn = next(gen)
    output = conn.send_command("show users")
    #process output...
    return processed_output

However this approach does not seem to be working in my case, as the
context-manager gets closed, and I get back a closed socket.

Is there a better way to approach this problem? Maybe my generator needs
some more work...I think using a generator to hold state is the most
"obvious" way that comes to mind, but overall should I be looking into
another way of keeping the session open across function calls?

Thanks


-- 
*Pablo Lucena*



More information about the Python-list mailing list