fab-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Fab-user] Collecting output when using Fabric directly in python


From: Jeff Forcier
Subject: Re: [Fab-user] Collecting output when using Fabric directly in python
Date: Tue, 18 Aug 2009 13:55:12 -0400

Hi Yann,

What you're asking for, then, isn't actually Fabric at all! :) since
the code you're talking about is simply calling Fabric code instead of
being Fabric-driven.

You can actually do this pretty easily; I've had to do it in order to
test Fabric itself, which is basically the same problem: run Fab code,
capturing output, then examining the output afterwards.

Check out the Fabric source and look in the 'tests' folder,
specifically tests/utils.py. It contains a single decorator,
@mock_streams, which is capable of wrapping a function (any function
in any Python code -- it's not Fabric specific, as I mentioned) and
redirecting sys.stdout and/or sys.stderr for capture/examination.

It's designed for use around functions, being a decorator, so you
could use it directly by modifying your fabfile_runner.py like so:

    from fabfile import hello_world

    from tests.utils import mock_streams # need to get 'tests' on pypath

    @mock_streams('stdout', 'stderr')
    def my_runner_function():
        hello_world()
        print "output : %s" % sys.stdout.getvalue()
        print "error : %s" % sys.stderr.getvalue()

If you don't actually have things organized in easily decorated functions, you
could just use the simple trick @mock_streams uses -- save the "real"
sys.stdout / sys.stderr as local variables and reassign those names to a
StringIO, which you can then examine programmatically.

If you need to actually have stdout/stderr go to the terminal AND be captured,
you'd need to go a little further, though I imagine it's still possible
somehow.

Hope that helps,
Jeff


On Tue, Aug 18, 2009 at 12:00 PM, Yann Malet<address@hidden> wrote:
> Jeff,
>
> This is nice improvement but I would like to see if possible is to capture
> both stdout and stderr into 2 python variables once a fabric Task is
> executed. Could you please help me to understand how you would do this and
> ideally without touching the fabfile.py
>
> I am going to take an example using 2 files :
>
> fabfile.py
> ---------8<-------------------------
> from fabric.api import *
> def hello_world():
>     """
>     Say hello to the world
>     """
>     print "hello world"
> ---------8<-------------------------
>
> fabfile_runner.py
> ---------8<-------------------------
> from fabfile import hello_world
> output = None
> error = None
> hello_world()
> print "output : %s" %output
> print "error : %s" %error
> ---------8<-------------------------
>
> It would be wonderful if you could explain me how I could  collect output
> and error by only modifying the file called fabfile_runner.py. Idealy the
> fabric task itself could be unmodified, this would allow to upload the the
> factory the same file that you have tested manually.
>
> Thank you very much for your kind explanation.
> Regards,
> Yann
>
> On Tue, Aug 18, 2009 at 11:04 AM, Jeff Forcier <address@hidden> wrote:
>>
>> On Sun, Aug 16, 2009 at 1:57 PM, Steve
>> Steiner<address@hidden> wrote:
>>
>> > Can this be done more nicely as a decorator since we've already got a
>> > Python
>> > 2.5+ requirement anyway?
>> >
>> > @capture_stderr
>> > def func_that_wants_stderr(...)
>> >        pass
>>
>> The main problem with this is that the stdout/stderr capturing is
>> per-run/sudo invocation and not per-task, so that doesn't mesh with
>> how I currently organize or think about things.
>>
>> That said, it did make me realize that there *might* be a use case for
>> making the settings() context manager (and/or others) into a decorator
>> in some fashion. In other words, if one currently needed to write
>> this:
>>
>>    def myfunc():
>>        with settings(warn_only=True):
>>            # stuff
>>
>> one could write the below modification, which would save a level of
>> indentation if you always need the entirety of the task "wrapped" in a
>> given settings change:
>>
>>   address@hidden(warn_only=True)
>>    def myfunc():
>>        # stuff
>>
>> So if we were to create a global setting for what run/sudo/local
>> capture, one could then do basically what you describe:
>>
>>   address@hidden(capture_stderr=True)
>>    def myfunc():
>>        this_would_be_stderr = run('foo')
>>
>> This is all just off the top of my head, still settling in after a
>> morning of traveling =)
>>
>> Best,
>> Jeff
>
>
> _______________________________________________
> Fab-user mailing list
> address@hidden
> http://lists.nongnu.org/mailman/listinfo/fab-user
>
>




reply via email to

[Prev in Thread] Current Thread [Next in Thread]