jquast / blessed

Blessed is an easy, practical library for making python terminal apps

Home Page:http://pypi.python.org/pypi/blessed

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to debug terminal applications made with `blessed`?

bzm3r opened this issue · comments

I like blessed very much, but I am having some issues with debugging applications with it. Using ipdb simply breaks IPython: http://stackoverflow.com/questions/37330720/attempting-to-debug-terminal-applications-made-with-pythonblessed-using-ipdb-br

And using pdb creates the following error:

Traceback (most recent call last):
  File "editor.py", line 49, in <module>
    main()
  File "editor.py", line 40, in main
    signal = mngr.handle_input(inp)
  File "/home/abcd/proofor/manager.py", line 272, in handle_input
    if inp == chr(3) or self.exit_signal_received:
  File "/home/abcd/proofor/manager.py", line 272, in handle_input
    if inp == chr(3) or self.exit_signal_received:
  File "/usr/lib/python2.7/bdb.py", line 49, in trace_dispatch
    return self.dispatch_line(frame)
  File "/usr/lib/python2.7/bdb.py", line 67, in dispatch_line
    self.user_line(frame)
  File "/usr/lib/python2.7/pdb.py", line 158, in user_line
    self.interaction(frame, None)
  File "/usr/lib/python2.7/pdb.py", line 210, in interaction
    self.cmdloop()
  File "/usr/lib/python2.7/cmd.py", line 113, in cmdloop
    self.old_completer = readline.get_completer()
AttributeError: 'module' object has no attribute 'get_completer'

So, how do you debug applications made with blessed?

I talked to @bmer about this and suggested pudb's remote debugging, the logging module in the standard library, and print statements to a file.

I'm facing the same issue. I want to have my IDE launch & debug the code, but have the blessed Terminal attached to another console/tty. Is that possible?

What about having it attach to a tmux session??

Thanks for the discussion, I nearly missed this issue.

I'm assuming editor.py uses the "with Terminal().cbreak()" or other context manager that modifies terminal settings, and that pdb's use of the readline library has some conflict with this.

I'd have to dig into pdb's source code, which I don't really mind, its a great program, to find out what the real problem is here. Perhaps there is some way we can "enable" mixing with pdb directly in blessed, let's hope!

And globally breaking your IPython installation -- wow!?

Glad that the example editor.py reproduces, I'll let you know if I can reproduce at home.

Problem

ipdb doesn't make any effort to prepare or restore terminal settings before yielding to IPython interface.

Curses programs must take special care to restore terminal settings when yielding control to another program, the python standard docs make a note of this, "A common problem when debugging a curses application is to get your terminal messed up when the application dies without restoring the terminal to its previous state. "

https://docs.python.org/3/howto/curses.html#starting-and-ending-a-curses-application

Details

Unlike the curses.wrapper function suggested by the internal docs, blessed uses contextlib.contextmanager for setting and restoring terminal state. To use a debugger for a curses application, we just need to ensure each context manager's "exit definition" is exercised.

In this github issue and linked stackoverflow question, you proposed to add ipdb.set_trace() after accepting user input in main loop of editor.py,

But this means the debugger is entered inside the scope of these context managers:

    with term.hidden_cursor(), \
            term.raw(), \
            term.location(), \
            term.fullscreen(), \
            term.keypad():

Solution

Invoke the debugger outside of the scope of these context managers.

Instead of directly invoking by ipdb.set_trace() inside of the with scope, raise an exception to be caught by an outer context manager, ipdb.launch_ipdb_on_exception().

To debug editor.py at line 224 as proposed, we would make the following changes:

diff --git a/bin/editor.py b/bin/editor.py
index 979b4e4..8983c3d 100755
--- a/bin/editor.py
+++ b/bin/editor.py
@@ -221,6 +221,7 @@ def main():
         while True:
             echo_yx(csr, term.reverse(screen.get((csr.y, csr.x), u' ')))
             inp = term.inkey()
+            raise ValueError

             if inp == chr(3):
                 # ^c exits
@@ -260,4 +261,6 @@ def main():
                 csr = n_csr

 if __name__ == '__main__':
-    main()
+    import ipdb
+    with ipdb.launch_ipdb_on_exception():
+        main()

@ohhorob I'm afraid your problem is something different than the one @bmer described. I would guess, you wish to develop with blessed, using an IDE which provides debugging (breakpoints, variable inspection, etc), but does not provide a terminal?

Can you name the IDE and File another issue if this is important to you?

It's IntelliJ IDEA, and they do provide a terminal.. however I haven't been able to use it with blessed.

I'll open up an issue to track..

I've found a decent workaround for the IDEA console limitations with scripts that need ANSI escape sequences.

I'm using the Python plugin to start a "remote debug" session. It waits for a connection from the script that wants to be debugged.

Then I configured an "External Tool" that uses AppleScript (osascript) to start a new iTerm tab and run a simple launcher bash script in that new terminal. The launcher activates the virtualenv of my project and sets some environment variables that my python scripts use. And finally launch the script.

When the script launches if it finds a PYDEVD_EGG environment variable, it will import it and connect to the debugger.

Now my blessed based python script has full and complete control over the iTerm tab it was launched in, but it's also connected to the pydevd IDE debugger too. I get to have my cake and eat it :)