What's the pythonic way to wrap several functions in the same with statements
Question: I am using the Python library,
[Fabric](http://docs.fabfile.org/en/1.4.3/index.html), to do some remote
server maintenance. Fabric automatically outputs all of the responses to
remote and local commands unless you wrap the command in a couple with
statements. Like so, on a local machine,

    
    
    with settings(warn_only='true'):
        with hide('running', 'stdout', 'stderr', 'warnings'):
            output = local("uname -a", True)
    

or like this on a remote machine:

    
    
    with settings(warn_only='true'):
        with hide('running', 'stdout', 'stderr', 'warnings'):
            output = run("uname -a")
    

I am writing a long and complex task and find myself repeating those two with
statements over and over again. I want to write a function called _mute() to
prevent that repetition. It would let me do something like this:

    
    
    def _mute(fabric_cmd, args):
        with settings(warn_only='true'):
            with hide('running', 'stdout', 'stderr', 'warnings'):
                output = fabric_cmd(args)
        return output
    
    def some_remote_task():
        # Run a remote task silently
        _mute(remote, 'uname -a')
    
    def some_local_task():
        # Run a local task silently
        _mute(local, 'uname -a', True)
    

I've looked into some solutions and know that "eval" could do this for me. But
every page I read about eval suggests that it's almost always a bad idea
because of security issues. I looked into partials, but I couldn't figure out
how to make an argument in my _mute function callable. I'm guessing there's a
higher level Python concept I'm missing here. What's the pythonic way to go
about doing this? Thanks for any direction you might be able to provide.


Answer: The better solution would be for you to build your own context manager; by far
the easiest way would be to use the [`contextlib.contextmanager`
decorator](http://docs.python.org/library/contextlib.html#contextlib.contextmanager):

    
    
    from contextlib import contextmanager
    
    @contextmanager
    def _mute():
        with settings(warn_only='true'):
            with hide('running', 'stdout', 'stderr', 'warnings'):
                yield
    

Then use `_mute` as a context manager:

    
    
    def some_remote_task():
        # Run a remote task silently
        with _mute():
            output = remote("uname -a")
    

This is a lot more compact and readable than having to retype the two larger
context manager lines and has the _added_ advantage that now you can run
multiple commands in that same context.

As for your question; you can easily apply arbitrary arguments to a given
function using the `*args` syntax:

    
    
    def _mute(fabric_cmd, *args):
        with settings(warn_only='true'):
            with hide('running', 'stdout', 'stderr', 'warnings'):
                return fabric_cmd(*args)
    
    def some_remote_task():
        # Run a remote task silently
        output = _mute(remote, 'uname -a')
    

See [*args and **kwargs?](http://stackoverflow.com/questions/3394835/args-and-
kwargs) for more information on the `*args` arbitrary argument lists tricks.

