Repository: web2py/web2py

Issue:
The integrated web-based debugger is broken with current MASTER branch
I've found that the integrated web-based debugger functionality (http://web2py.com/books/default/chapter/29/03/overview?search=debugger#Integrated-web-based-debugger) is broken with current MASTER branch - while it works fine with the current static source.

In particular, adding the lines:

```
from gluon.debug import dbg
dbg.set_trace()
```
 
to the standard Welcome app gives the following traceback (with Python 2.7 and 3.5, too)

<type 'exceptions.AttributeError'> Qdb instance has no attribute 'Frontend'

  File "/home/nicoz/web2py-master.27/gluon/restricted.py", line 216, in restricted
    exec(ccode, environment)
  File "/home/nicoz/web2py-master.27/applications/admin/controllers/debug.py:interact", line 238, in <module>
  File "/home/nicoz/web2py-master.27/gluon/globals.py", line 405, in <lambda>
    self._caller = lambda f: f()
  File "/home/nicoz/web2py-master.27/applications/admin/controllers/debug.py:interact", line 49, in interact
  File "/home/nicoz/web2py-master.27/gluon/debug.py", line 131, in run
    dbg.Frontend.run(self)
AttributeError: Qdb instance has no attribute 'Frontend'
In file: /home/nicoz/web2py-master.27/applications/admin/controllers/debug.py

I've wrote this to Mariano Reingart, and he told me that it looks like a naming collision, and to try to comment the following line (gluon/debug.py:190):

https://github.com/web2py/web2py/blob/master/gluon/debug.py#L190

For example:

# dbg = dbg_debugger

But this didn't work either, giving the traceback:

  File "/home/nicoz/web2py-static.27/gluon/main.py", line 447, in wsgibase
    gluon.debug.dbg.do_debug(mainpyfile=request.folder)
AttributeError: 'module' object has no attribute 'dbg'



Discussion:

Resolving patch:
diff --git a/applications/admin/controllers/debug.py b/applications/admin/controllers/debug.py
--- a/applications/admin/controllers/debug.py
+++ b/applications/admin/controllers/debug.py
@@ -6,6 +6,7 @@
 import code
 from gluon.debug import communicate, web_debugger, dbg_debugger
 from gluon._compat import thread
+from gluon.fileutils import open_file
 import pydoc
 
 
@@ -54,7 +55,7 @@ def interact():
     if filename:
         # prevent IOError 2 on some circuntances (EAFP instead of os.access)
         try:
-            lines = open(filename).readlines()
+            lines = open_file(filename, 'r').readlines()
         except:
             lines = ""
         lines = dict([(i + 1, l) for (i, l) in enumerate(
diff --git a/gluon/compileapp.py b/gluon/compileapp.py
--- a/gluon/compileapp.py
+++ b/gluon/compileapp.py
@@ -637,7 +637,7 @@ def run_controller_in(controller, function, environment):
                        web2py_error=badf)
         code = "%s\nresponse._vars=response._caller(%s)" % (code, function)
         layer = "%s:%s" % (filename, function)
-        ccode = getcfs(layer, filename, lambda: compile2(code, layer))
+        ccode = getcfs(layer, filename, lambda: compile2(code, filename))
 
     restricted(ccode, environment, layer=filename)
     response = environment["response"]
diff --git a/gluon/debug.py b/gluon/debug.py
--- a/gluon/debug.py
+++ b/gluon/debug.py
@@ -89,7 +89,7 @@ def communicate(command=None):
 
 # New debugger implementation using dbg and a web UI
 
-import gluon.contrib.dbg as dbg
+import gluon.contrib.dbg as c_dbg
 from threading import RLock
 
 interact_lock = RLock()
@@ -109,11 +109,11 @@ def check_fn(self, *args, **kwargs):
     return check_fn
 
 
-class WebDebugger(dbg.Frontend):
+class WebDebugger(c_dbg.Frontend):
     """Qdb web2py interface"""
 
     def __init__(self, pipe, completekey='tab', stdin=None, stdout=None):
-        dbg.Frontend.__init__(self, pipe)
+        c_dbg.Frontend.__init__(self, pipe)
         self.clear_interaction()
 
     def clear_interaction(self):
@@ -128,7 +128,7 @@ def run(self):
         run_lock.acquire()
         try:
             while self.pipe.poll():
-                dbg.Frontend.run(self)
+                c_dbg.Frontend.run(self)
         finally:
             run_lock.release()
 
@@ -149,23 +149,23 @@ def exception(self, title, extype, exvalue, trace, request):
 
     @check_interaction
     def do_continue(self):
-        dbg.Frontend.do_continue(self)
+        c_dbg.Frontend.do_continue(self)
 
     @check_interaction
     def do_step(self):
-        dbg.Frontend.do_step(self)
+        c_dbg.Frontend.do_step(self)
 
     @check_interaction
     def do_return(self):
-        dbg.Frontend.do_return(self)
+        c_dbg.Frontend.do_return(self)
 
     @check_interaction
     def do_next(self):
-        dbg.Frontend.do_next(self)
+        c_dbg.Frontend.do_next(self)
 
     @check_interaction
     def do_quit(self):
-        dbg.Frontend.do_quit(self)
+        c_dbg.Frontend.do_quit(self)
 
     def do_exec(self, statement):
         interact_lock.acquire()
@@ -175,18 +175,18 @@ def do_exec(self, statement):
                 # avoid spurious interaction notifications:
                 self.set_burst(2)
                 # execute the statement in the remote debugger:
-                return dbg.Frontend.do_exec(self, statement)
+                return c_dbg.Frontend.do_exec(self, statement)
         finally:
             interact_lock.release()
 
 # create the connection between threads:
 
 parent_queue, child_queue = Queue.Queue(), Queue.Queue()
-front_conn = dbg.QueuePipe("parent", parent_queue, child_queue)
-child_conn = dbg.QueuePipe("child", child_queue, parent_queue)
+front_conn = c_dbg.QueuePipe("parent", parent_queue, child_queue)
+child_conn = c_dbg.QueuePipe("child", child_queue, parent_queue)
 
 web_debugger = WebDebugger(front_conn)                                     # frontend
-dbg_debugger = dbg.Qdb(pipe=child_conn, redirect_stdio=False, skip=None)   # backend
+dbg_debugger = c_dbg.Qdb(pipe=child_conn, redirect_stdio=False, skip=None)   # backend
 dbg = dbg_debugger
 
 # enable getting context (stack, globals/locals) at interaction


Test patch: