1. eduardo schettino
  2. doit
  3. Issues


Issue #36 resolved

No isatty() method in action.Writer

José Esteves
created an issue

Class doit.action.Writer lacks a isatty() method. I suppose it would be nice to have one, but I'm not acquainted enough with sufficient stuff, including doit's code, to be sure of the most appropriate definition for isatty() there... — e.g., sane to returne True whenever sys.stdout.isatty() is True?

By the way, this showed up in the context of starting to try fabric combined with doit [*], just a small test of calling fabric's run() from a doit python action, getting the exception "AttributeError: 'Writer' object has no attribute 'isatty'". No errors if I call run(... pty=False) (http://docs.fabfile.org/en/1.5/usage/interactivity.html#pseudottys ).

[*] The thought of combining the power of doit with fabric+cuisine (http://www.slideshare.net/ffunction/fabric-cuisine-and-watchdog-for-server-administration-in-python ) for Pythonic system config management feels… interesting™ :)

Comments (7)

  1. José Esteves reporter

    Haven't tried the suggestion in #18 specifically yet [hectic day] but I suppose any sensible isatty() definition will be appropriate, in the sense that the AttributeError will go away and that often the tasks one defines are supposed to 'withstand' situations where isatty() is False. Unless perhaps one intends to run tasks only interactively and something fails, but I was able to e.g. run passwd remotely with no doit changes, simply using fabric's run (..., pty=False) (with the disadvantage of having password input echoed back, as fabric's docs mention).

    While playing a bit, to see if I should expect any other problems running fabric's execute () in doit actions, I actually added a brute-force isatty method definition in my dodo.py to avoid that exception.

    import types
    from doit import action
    def fakeisatty (self):
        return True
    action.Writer.isatty = types.UnboundMethodType(fakeisatty, None, action.Writer)

    and met no other issues (then invoking run with pty=True, the default), at least not for now. Anyway, I'm most likely to use fabric+doit in situations with no need for terminal interaction — simply running fabric tasks with pty=False would suffice.

    Also tried PythonInteractiveAction, as you suggested — no isatty-related exception, and apparently no other failures. Not sure if it would always be an appropriate choice, but that's because I haven't yet seen if any differences in it make it a worse choice than the unwrapped action in what I'll be running.

  2. José Esteves reporter

    Applied the changes you suggest in #18 to a fresh checkout, tested for a bit, and it seems to run nicely, so far, even with something like 'su -' (then interactively working on the remote shell) or 'top' as commands remotely invoked via Fabric's run() (in a Fabric task function, invoked for a few machines via Fabric's execute() in a doit Python action).

  3. eduardo schettino repo owner

    First let me explain how doit works

    doit will save all stdout and stderr for any task's actions.

    In doit you can control "verbosity" of the task execution, that controls if you gonna see the action's output in realtime (on the terminal) while the task is being executed (by default it hides stdout and shows stderr). If a task fails it will display both stdout and stderr at the end.

    For a cmd-action doit will capture the output from the child process and based on the verbosity decide if the captured output will be written in the terminal. So a process executed by cmd-action will always se isatty==False.

    For python-action has this Writer class that is actually a group of streams. It will always contain a StringIO used to save the output and dependending on the verbosity it will also contain a stream to the terminal. To achieve same behavior of cmd-action you just need to set isatty==False.

    This "interactive actions" in tools.py will not capture stdin/stdout and will always put send both stdout/stderr to the terminal. So the action will just interact directly with the terminal running doit. The disavantage is that you cant save the output nor control its verbosity. These "interactive actions" can get user input from the terminal while normal action can not.


    1) normal actions dont handle user input. how can it handle input if running multiple tasks in parallel ?

    2) on parallel task execution the output should contain the information from which task/process it is coming from.

    3) when a running a task the output can be both a tty(display on terminal) and not a tty (doit saves the output). so I guess the user should have control to explicitly set this.

    4) there is also the problem of controlling line/byte buffering.

    I am planning for sometime to re-write this output handling to fix issue 2 & 4. but not on my schedule :D

    If you are not worried about user input... and you think my patch #18 is good enough I can just merge it. does that solve your problem? If yes, could you give a shot in writing a unit-test?

  4. Log in to comment