Package: wdb.server.aiohttp
wdb[aiohttp] - Web DebuggerAbout this projectThis is not originalwdb.server, originalwdb.serverplacedhereWhy?Original project was written more that 6 years ago, withtornadoon backend andcoffescript/bower/grunton frontend.
These are very old technologies. I wanted to be able to expand functionality and fix bugs.
But I don't want to study and support the product based on old technologies.What's difference beetween original wdb.server and this projectTornado -> aiohttpCoffescript -> TypescriptBower -> npmGrunt -> Webpackyapf -> blackAdded support of themes for any screenAdded responsibility forPROCESSEStabAdded support of Safariwdb now works without internet access(original project required Google fonts from CDN)100% Code coverageUsed alpine base imageWhat's plans?ChangeCodeMirror->MonacoCover frontend with unit testsAdd integration tests frontend <-> backendAdd support of multithread/multiprocess/async deebuggingDescriptionwdbis a full featured web debugger based on a client-server architecture.The wdb server which is responsible of managing debugging instances along with browser connections (through websockets) is based onaiohttp.
The wdb clients allow step by step debugging, in-program python code execution, code edition (based onCodeMirror) setting breakpoints...Due to this architecture, all of this is fully compatible withmultithreadandmultiprocessprograms.wdbworks with python 2 (2.6, 2.7), python 3 (3.2, 3.3, 3.4, 3.5) and pypy.
Even better, it is possible to debug a python 2 program with a wdb server running on python 3 and vice-versa or debug a program running on a computer with a debugging server running on another computer inside a web page on a third computer!Even betterer, it is now possible to pause a currently running python process/thread using code injection from the web interface. (This requires gdb and ptrace enabled)In other words it's a very enhanced version of pdb directly in your browser with nice features.Installation:Global installation:$ pip install wdb.server.aiohttpIn virtualenv or with a different python installation:$ pip install wdb(You must have the server installed and running)Quick testTo try wdb, first you have to start the wdb server:$ wdb.server.py &Next run:$ python -m wdb your_file.pyWdb will open a debugging window right in your browser, paused at the beginning of your program.You can access tohttp://localhost:1984/to have an overview of the server.NB: You have to start the server only once. Multiple Debugging sessions can be run simultaneously without problem.This is not the only way to debug a program, see below.UsageSetting traceTo debug any program, with the server on, just add:importwdbwdb.set_trace()anywhere in your code. Your program will stop at the set_trace line. (Just like pdb)Tracing codeTo inspect your code on exception, you can do the following:fromwdbimporttracewithtrace():wrong_code()Any exception duringwrong_codewill launch a debugging session.You can also use thestart_trace()andstop_tracemethods.
(It's better to put thestop_tracein a finally block to avoid tracing all your program after an exception.)Debugging web serverswdb provides some tools to make it work nicely with different webservers:Wsgi serversFor wsgi servers you can use theWdbMiddleware:fromwdb.extimportWdbMiddlewarewsgi_app=Whathever_wsgi_server_lib()my_app=WdbMiddleware(wsgi_app)my_app.serve_forever()Flaskor using Flask:fromflaskimportFlaskfromwdb.extimportWdbMiddlewareapp=Flask(__name__)app.debug=Trueapp.wsgi_app=WdbMiddleware(app.wsgi_app)app.run(use_debugger=False)# Disable builtin Werkzeug debuggeryou can also use theFlask-WdbextensionfromflaskimportFlaskfromflask_wdbimportWdbapp=Flask(__name__)app.debug=TrueWdb(app)app.run()Djangoor using django:Add the middleware in yourwsgi.py:After:fromdjango.core.wsgiimportget_wsgi_applicationapplication=get_wsgi_application()Add this:fromwdb.extimportWdbMiddlewareapplication=WdbMiddleware(application)And in yoursettings.py, activate exception propagation:DEBUG=TrueDEBUG_PROPAGATE_EXCEPTIONS=TrueCherryPyor using CherryPy:importcherrypyfromwdb.extimportWdbMiddlewareclassHelloWorld(object):@cherrypy.exposedefindex(self):undefined_method()# This will failreturn"Hello World!"cherrypy.config.update({'global':{'request.throw_errors':True}})app=cherrypy.Application(HelloWorld())app.wsgiapp.pipeline.append(('debugger',WdbMiddleware))cherrypy.quickstart(app)TornadoIn tornado, which is not a wsgi server, you can use thewdb_tornadofunction which will monkey patch the execute method on RequestHandlers:fromwdb.extimportwdb_tornadofromtornado.webimportApplicationmy_app=Application([(r"/",MainHandler)])ifoptions.debug:wdb_tornado(my_app)my_app.listen(8888)Page loading time become slowIf wdb slows down too much of your application (tracing all the things takes time), you can start it disabled with:my_app=WdbMiddleware(wsgi_app,start_disabled=True)# orwdb_tornado(my_app,start_disabled=True)Then when you get an exception just click on the on/off button.Remote debuggingYou can easily do remote debugging with wdb:Let's say you want to run a programp.pyon computer A and you want to debug it on computer B.Start wdb server on computer A and launch this:WDB_NO_BROWSER_AUTO_OPEN=True python -m wdb p.pyAnd open a browser on computer B at the url given by wdb log.Now you can also run wdb server on a computer C and run on computer A:WDB_NO_BROWSER_AUTO_OPEN=True WDB_SOCKET_SERVER=computerC.addr WDB_SOCKET_PORT=19840 python -m wdb p.pyAnd go with computer B tohttp://computerC/debug/session/[uuidin log] there you can step into p.py running in computer A. Yay !You can use different configurations:Seewdb.server.py --helpfor changing ports on server and these environnement vars for wdb instances:WDB_SOCKET_SERVER         # WDB server host
WDB_SOCKET_PORT           # WDB server socket port
WDB_WEB_SERVER            # WDB server host for browser openning
WDB_WEB_PORT              # WDB server http port
WDB_NO_BROWSER_AUTO_OPEN  # To disable the automagic browser openning (which can't be done if the browser is not on the same machine)DockerIf you are developing locally withDocker, you can
also use wdb to debug a code running inside a container. The basic setup looks
like this:Startwdb.server.pyrunning in a container and expose port1984to your
host computer, this will server the debugging web server.Start debugging in your app container, making sure to setWDB_SOCKET_SERVERto the address of the server container, and point it to the expoed port19840on that server.When a trace is reached, open uphttp://<your-docker-hostname>:1984I will walk through this process in detail, usingDocker Composeto set up the containers.Let's say yourdocker-compose.ymllooks liketheir example for using with Django:db:image:postgresweb:build:.command:python manage.py runserver 0.0.0.0:8000volumes:-.:/codeports:-"8000:8000"links:-dbNext lets add the wdb server part now and tell the web to link to it:db:image:postgresweb:build:.command:python manage.py runserver 0.0.0.0:8000volumes:-.:/codeports:-"8000:8000"links:-db-wdbenvironment:WDB_SOCKET_SERVER:wdbWDB_NO_BROWSER_AUTO_OPEN:Truewdb:image:shepilov-vladislav/wdbports:-"1984:1984"And addwdbto yourrequirements.txtin your web app:$echo'wdb'>>requirements.txtNow we can usewdb.set_trace()in our python app.# ... some codeimportwdbwdb.set_trace()Then you have to rebuild your web application and start everything up again$docker-composestop
$docker-composebuildweb
$docker-composeupNow you can accesshttp://<local docker server>:1984, to
see the traces as they come up in your app.In browser usageOnce you are in a breakpoint or in an exception, you can eval all you want in the prompt under the code.
Multi-lines are partially supported using[Shift] + [Enter].
There is now help available by clicking on the top help button.As of now the following special commands are supported during breakpoint:* .s or [Ctrl] + [↓] or [F11]    : Step into
* .n or [Ctrl] + [→] or [F10]    : Step over (Next)
* .r or [Ctrl] + [↑] or [F9]     : Step out (Return)
* .c or [Ctrl] + [←] or [F8]     : Continue
* .u or [F7]                     : Until (Next over loops)
* .j lineno                      : Jump to lineno (Must be at bottom frame and in the same function)
* .b arg                         : Set a session breakpoint, see below for what arg can be*
* .t arg                         : Set a temporary breakpoint, arg follow the same syntax as .b
* .z arg                         : Delete existing breakpoint
* .l                             : List active breakpoints
* .f                             : Echo all typed commands in the current debugging session
* .d expression                  : Dump the result of expression in a table
* .w expression                  : Watch expression in current file (Click on the name to remove)
* .q                             : Quit
* .h                             : Get some help
* .e                             : Toggle file edition mode
* .g                             : Clear prompt
* .i [mime/type;]expression      : Display the result in an embed, mime type is auto detected on linux and defaults to "text/html" otherwise
* iterable!sthg                  : If cutter is installed, executes cut(iterable).sthg
* expr >! file                   : Write the result of expr in file
* !< file                        : Eval the content of file
* [Enter]                        : Eval the current selected text in page, useful to eval code in the source
*
* * arg is using the following syntax:
*   [file/module][:lineno][#function][,condition]
* which means:
*   - [file]                    : Break if any line of `file` is executed
*   - [file]:lineno             : Break on `file` at `lineno`
*   - [file][:lineno],condition : Break on `file` at `lineno` if `condition` is True (ie: i == 10)
*   - [file]#function           : Break when inside `function` function
*
* File is always current file by default and you can also specify a module like `logging.config`.You can also eval a variable in the source by middle clicking on it.
You can add/remove a breakpoint by clicking on the line number.NB: Hotkeys with arrows are purposely not triggered in the eval prompt to avoid conflicts when typing.Wdb ServerTo see which debugging session are currently open, open your browser athttp://localhost:1984/.
You can also close crashed session.From there you should also see all python process and their threads running and you can try to pause them during their execution to do step by step debugging and current variable inspection.This is highly experimental and requires gdb and a kernel with ptrace enabled to inject python code into a running python process.If you getptrace: Operation not permitted.you will have to enable it.Depending on your system it might work with:echo0|sudotee/proc/sys/kernel/yama/ptrace_scopeMake sure that wdb is installed for the python version running the program too.Importing wdb each time is exhaustingYes to avoid that, you can add awbuiltin at the beggining of your application:fromwdb.extimportadd_w_builtinadd_w_builtin()you can now use thewobject any where in your code:my_code()w.tf# Stop next linedoubtful_code()my_code()withw.trace():doubtful_code()Code completionWdb has dynamic code completion in eval prompt thanks tojedi.FAQIn Firefox opened debugging pages are not closed when doneIt's a firefox config flag, visitabout:configand set:dom.allow_scripts_to_close_windowstotrueThe logs are spammed with 'parsing Python module'If your logging configuration is set to display DEBUG logs, you may see a log for every imported file in your project any time WDB is active, like so:DEBUG 2017-07-16 13:15:03,772 index 49835 123145573191680 parsing Python module /project/.virtualenv/python-3.6.1/lib/python3.6/site-packages/package/file.py for indexingTo silence only this message, add a config for the importmagic module. For example:LOGGING = {
    ...
    'loggers': {
        ...
        'importmagic.index': {
            'level': 'ERROR',
            'propagate': False,
        },
    },
}ContributeAll contributions are more than welcomed, use the fork luke !AuthorFlorian Mounier@KozeaShepilov VladislavLicenceThis library is licensed under GPLv3