Giter Club home page Giter Club logo

wdb's Introduction

wdb - Web Debugger

Build Status Coverage Status

Description

wdb is 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 on Tornado. The wdb clients allow step by step debugging, in-program python code execution, code edition (based on CodeMirror) setting breakpoints...

Due to this architecture, all of this is fully compatible with multithread and multiprocess programs.

wdb works 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

In virtualenv or with a different python installation:

    $ pip install wdb

(You must have the server installed and running)

Quick test

To try wdb, first you have to start the wdb server:

    $ wdb.server.py &

Optionally, you can automatically activate daemons with systemd (socket activation):

    $ cd /etc/systemd/system
    # curl -O https://raw.githubusercontent.com/Kozea/wdb/master/server/wdb.server.service
    # curl -O https://raw.githubusercontent.com/Kozea/wdb/master/server/wdb.server.socket
    # systemctl enable wdb.server.socket
    # systemctl start wdb.server.socket

Next run:

    $ python -m wdb your_file.py

Wdb will open a debugging window right in your browser, paused at the beginning of your program.

You can access to http://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.

Usage

Setting trace

To debug any program, with the server on, just add:

    import wdb
    wdb.set_trace()

anywhere in your code. Your program will stop at the set_trace line. (Just like pdb)

Tracing code

To inspect your code on exception, you can do the following:

    from wdb import trace
    with trace():
        wrong_code()

Any exception during wrong_code will launch a debugging session.

You can also use the start_trace() and stop_trace methods. (It's better to put the stop_trace in a finally block to avoid tracing all your program after an exception.)

Debugging web servers

wdb provides some tools to make it work nicely with different webservers:

Wsgi servers

For wsgi servers you can use the WdbMiddleware:

    from wdb.ext import WdbMiddleware
    wsgi_app = Whathever_wsgi_server_lib()
    my_app = WdbMiddleware(wsgi_app)
    my_app.serve_forever()
Flask

or using Flask:

    from flask import Flask
    from wdb.ext import WdbMiddleware
    app = Flask(__name__)
    app.debug = True
    app.wsgi_app = WdbMiddleware(app.wsgi_app)
    app.run(use_debugger=False) # Disable builtin Werkzeug debugger

you can also use the Flask-Wdb extension

    from flask import Flask
    from flask_wdb import Wdb

    app = Flask(__name__)
    app.debug = True
    Wdb(app)

    app.run()
Django

or using django:

Add the middleware in your wsgi.py:

After:

    from django.core.wsgi import get_wsgi_application
    application = get_wsgi_application()

Add this:

    from wdb.ext import WdbMiddleware
    application = WdbMiddleware(application)

And in your settings.py, activate exception propagation:

    DEBUG = True
    DEBUG_PROPAGATE_EXCEPTIONS = True
CherryPy

or using CherryPy:

import cherrypy
from wdb.ext import WdbMiddleware

class HelloWorld(object):
    @cherrypy.expose
    def index(self):
        undefined_method() # This will fail
        return "Hello World!"

cherrypy.config.update({'global':{'request.throw_errors': True}})
app = cherrypy.Application(HelloWorld())
app.wsgiapp.pipeline.append(('debugger', WdbMiddleware))

cherrypy.quickstart(app)

Tornado

In tornado, which is not a wsgi server, you can use the wdb_tornado function which will monkey patch the execute method on RequestHandlers:

    from wdb.ext import wdb_tornado
    from tornado.web import Application
    my_app = Application([(r"/", MainHandler)])
    if options.debug:
        wdb_tornado(my_app)
    my_app.listen(8888)

Page loading time become slow

If 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)  # or
    wdb_tornado(my_app, start_disabled=True)

Then when you get an exception just click on the on/off button.

Remote debugging

You can easily do remote debugging with wdb:

Let's say you want to run a program p.py on 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.py

And 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.py

And go with computer B to http://computerC/debug/session/[uuid in log] there you can step into p.py running in computer A. Yay !

You can use different configurations:

See wdb.server.py --help for 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)

Docker

If you are developing locally with Docker, you can also use wdb to debug a code running inside a container. The basic setup looks like this:

  1. Start wdb.server.py running in a container and expose port 1984 to your host computer, this will server the debugging web server.
  2. Start debugging in your app container, making sure to set WDB_SOCKET_SERVER to the address of the server container, and point it to the expoed port 19840 on that server.
  3. When a trace is reached, open up http://<your-docker-hostname>:1984

I will walk through this process in detail, using Docker Compose to set up the containers.

Let's say your docker-compose.yml looks like their example for using with Django:

db:
  image: postgres
web:
  build: .
  command: python manage.py runserver 0.0.0.0:8000
  volumes:
    - .:/code
  ports:
    - "8000:8000"
  links:
    - db

Next lets add the wdb server part now and tell the web to link to it:

db:
  image: postgres
web:
  build: .
  command: python manage.py runserver 0.0.0.0:8000
  volumes:
    - .:/code
  ports:
    - "8000:8000"
  links:
    - db
    - wdb
  environment:
    WDB_SOCKET_SERVER: wdb
    WDB_NO_BROWSER_AUTO_OPEN: True
wdb:
  image: kozea/wdb
  ports:
    - "1984:1984"

And add wdb to your requirements.txt in your web app:

$ echo 'wdb' >> requirements.txt

Now we can use wdb.set_trace() in our python app.

# ... some code
import wdb
wdb.set_trace()

Then you have to rebuild your web application and start everything up again

$ docker-compose stop
$ docker-compose build web
$ docker-compose up

Now you can access http://<local docker server>:1984, to see the traces as they come up in your app.

In browser usage

Once 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 Server

To see which debugging session are currently open, open your browser at http://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 get ptrace: Operation not permitted. you will have to enable it.

Depending on your system it might work with:

echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope

Make sure that wdb is installed for the python version running the program too.

Importing wdb each time is exhausting

Yes to avoid that, you can add a w builtin at the beggining of your application:

    from wdb.ext import add_w_builtin
    add_w_builtin()

you can now use the w object any where in your code:

    my_code()
    w.tf  # Stop next line
    doubtful_code()
    my_code()
    with w.trace():
        doubtful_code()

Code completion

Wdb has dynamic code completion in eval prompt thanks to jedi.

FAQ

In Firefox opened debugging pages are not closed when done

It's a firefox config flag, visit about:config and set: dom.allow_scripts_to_close_windows to true

The 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 indexing

To silence only this message, add a config for the importmagic module. For example:

LOGGING = {
    ...
    'loggers': {
        ...
        'importmagic.index': {
            'level': 'ERROR',
            'propagate': False,
        },
    },
}

Contribute

All contributions are more than welcomed, use the fork luke !

Or you still can use your money =)

Flattr gittip

Test

Wdb is now partially tested, so if you want to contribute be sure to run the test suite:

    $ pip install pytest
    $ pip install -e client -e server
    $ cd test
    $ py.test

Feel free to add tests !

Author

Florian Mounier @ Kozea

Licence

This library is licensed under GPLv3

wdb - An improbable web debugger through WebSockets

wdb Copyright (c) 2012-2016  Florian Mounier, Kozea

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

wdb's People

Contributors

akalipetis avatar akatrevorjay avatar eddiejessup avatar kyso avatar le-stagiaire avatar lize avatar orthographic-pedant avatar paradoxxxzero avatar ptim avatar s0undt3ch avatar saulshanabrook avatar securecommi avatar techniq avatar tuxcanfly avatar wong2 avatar yajo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wdb's Issues

Repr inspection

In the eval prompt, objects are displayed with their repr.
It seems more than usefull to allow inspection of these objects, on click for example.

Attempting to prettify log messages when not a tty.

You perhaps should not be trying to prettify log messages, eg., bold, when you can determine that it is not being output to a tty.

[Tue May 13 08:17:56 2014] [error] \x1b[0m\x1b[31m2014-05-13 08:17:56,837 \x1b[1m\x1b[31mwdb handle_exception:662 \x1b[0m Exception during trace
[Tue May 13 08:17:56 2014] [error] Traceback (most recent call last):
[Tue May 13 08:17:56 2014] [error]   File "/Users/graham/Projects/mod_wsgi-4.1/lib/python2.7/site-packages/wdb/ext.py", line 70, in trace_wsgi
[Tue May 13 08:17:56 2014] [error]     for item in appiter:
[Tue May 13 08:17:56 2014] [error]   File "/Users/graham/Projects/mod_wsgi-4.1/tests/environ.wsgi", line 19, in application
[Tue May 13 08:17:56 2014] [error]     xxx
[Tue May 13 08:17:56 2014] [error] NameError: global name 'xxx' is not defined\x1b[0m
[Tue May 13 08:17:56 2014] [error] \x1b[0m\x1b[33m2014-05-13 08:17:56,838 \x1b[1m\x1b[33mwdb handle_exception:671 \x1b[0m trace_wsgi </Users/graham/Projects/mod_wsgi-4.1/lib/python2.7/site-packages/wdb/ext.py:70>\x1b[0m

UnicodeDecodeError: 'utf8' codec can't decode byte 0x88 in position 9: invalid start byte

Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/wdb/ui.py", line 115, in loop
    stop = self.interact()
  File "/usr/local/lib/python2.7/dist-packages/wdb/ui.py", line 155, in interact
    return fun(data)
  File "/usr/local/lib/python2.7/dist-packages/wdb/ui.py", line 271, in do_eval
    '\n'.join(out) + '\n'.join(err))
  File "/usr/local/lib/python2.7/dist-packages/wdb/ui.py", line 26, in dump
    return dumps(o, cls=ReprEncoder, sort_keys=True)
  File "/usr/lib/python2.7/json/__init__.py", line 238, in dumps
    **kw).encode(obj)
  File "/usr/lib/python2.7/json/encoder.py", line 203, in encode
    chunks = list(chunks)
  File "/usr/lib/python2.7/json/encoder.py", line 428, in _iterencode
    for chunk in _iterencode_dict(o, _current_indent_level):
  File "/usr/lib/python2.7/json/encoder.py", line 384, in _iterencode_dict
    yield _encoder(value)
UnicodeDecodeError: 'utf8' codec can't decode byte 0x88 in position 9: invalid start byte

ValueError: too many values to unpack

Traceback (most recent call last):
  File "/home/joejev/.virtualenvs/qexec/lib/python2.7/site-packages/wdb/ui.py", line 155, in loop
    stop = self.interact()
  File "/home/joejev/.virtualenvs/qexec/lib/python2.7/site-packages/wdb/ui.py", line 192, in interact
    rv = fun(data)
  File "/home/joejev/.virtualenvs/qexec/lib/python2.7/site-packages/wdb/ui.py", line 386, in do_break
    remaining, cond = remaining.split(',')
ValueError: too many values to unpack

Document required browser versions

I could not get wdb to work with Chrome 22.0.1229.94 (specifically: attempting to evaluate anything had no result, possibly an issue communicating with the server - e.g. with python -m wdb.test and simply typing something like 'True' with no server response).
But by chance, it did work with an upgrade to 24.0.1312.70 and with Firefox 18.0.1.

If anything even approximately is known about what minimum required versions of which browsers will work, it would be nice to tell that to users in the README so they do not just think wdb itself is broken just because they have let their browser get a bit out of date :)

Google App Engine?

I'm inquiring about whether you think wdb could be used for debugging a WSGI application running on the Google App Engine (GAE) dev server.

Here are three problems I was able to find in following the wdb README instructions:

  1. When one sets up the GAE SDK, the set up makes the dev_appserver.py script available for starting your application. So I can go to the root directory of my app and run dev_appserver.py to start the app. However, python -m wdb dev_appserver.py results in this error being immediately printed to the terminal: ('Error:', '/absolute/path/to/project/dev_appserver.py', 'does not exist'). This isn't surprising, though, because dev_appserver.py is not collocated with my application.
  2. I then tried using the absolute path to the script, which is located with the GAE SDK: python -m wdb $(which dev_appserver.py). The wdb server successfully begins, but files that are collocated with the dev_appserver.py script cannot be properly loaded by dev_appserver.py, so an import error crashes the GAE server before my app can begin serving.
  3. I went ahead and tried importing wdb somewhere in my application without actually trying to run the application from wdb (i.e., I ran the app directly via dev_appserver.py). The following error was raised: ImportError: No module named pwd. I'm guessing that wdb imports the pwd module. The GAE sandbox prevents the pwd module from being imported in a running application by not whitelisting it (source).

Unable to launch wdb server.

I just installed wdb and tried to launch, but faced with the following error message. I'm running OS X. I installed it via pip install wdb.server.

amjith@amjith-mbp: ~/Dropbox/code/python/pgcli master ⚡
$ wdb.server.py
Traceback (most recent call last):
  File "/usr/local/bin/wdb.server.py", line 2, in <module>
    from wdb_server import server
  File "/usr/local/lib/python2.7/site-packages/wdb_server/__init__.py", line 241, in <module>
    from wdb_server.utils import refresh_process, LibPythonWatcher
  File "/usr/local/lib/python2.7/site-packages/wdb_server/utils.py", line 23, in <module>
    import psutil
  File "/usr/local/lib/python2.7/site-packages/psutil/__init__.py", line 149, in <module>
    import psutil._psosx as _psplatform
  File "/usr/local/lib/python2.7/site-packages/psutil/_psosx.py", line 168, in <module>
    pids = cext.pids
AttributeError: 'module' object has no attribute 'pids'
FAIL: 1

amjith@amjith-mbp: ~/Dropbox/code/python/pgcli master ⚡
$ pip freeze | grep wdb
wdb==2.0.7
wdb.server==2.0.7

amjith@amjith-mbp: ~/Dropbox/code/python/pgcli master ⚡
$ pip freeze | grep psutil
psutil==2.2.0

ValueError: No JSON object could be decoded

Browser shows this error as soon as I type a character:

Client Server version mismatch !
Server is 2.1.1 and Client is 2.1.8
Error in Wdb, this is bad
ValueError: No JSON object could be decoded
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/wdb/ui.py", line 171, in loop
    stop = self.interact()
  File "/usr/local/lib/python2.7/dist-packages/wdb/ui.py", line 208, in interact
    rv = fun(data)
  File "/usr/local/lib/python2.7/dist-packages/wdb/ui.py", line 545, in do_complete
    completion = loads(data)
  File "/usr/lib/python2.7/json/__init__.py", line 326, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python2.7/json/decoder.py", line 366, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python2.7/json/decoder.py", line 384, in raw_decode
    raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

WdbMiddleware theme error: no theme argument

The document says that we can choose a theme in these way

    wdb.server --theme=light  # and if you disable the debugger
    WdbMiddleware(app, theme='light') # or
    wdb_tornado(app, theme='light')

But the fact is that in wdb/ext.py the WdbMiddleware.init doesn't have the param "theme"

class WdbMiddleware(object):
    def __init__(self, app, start_disabled=False):
        self.app = app
        Wdb.enabled = not start_disabled

So I got the Error:

WdbMiddleware(app.wsgi_app, False, theme='dark')
TypeError: __init__() got an unexpected keyword argument 'theme'

environment:
wdb==2.1.8 # installed from pip
ubuntu 14.04
python2.7

ValueError: No JSON object could be decoded

Writing in the interpreter any letter yields this.

Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/wdb/ui.py", line 171, in loop
    stop = self.interact()
  File "/usr/lib/python2.7/site-packages/wdb/ui.py", line 208, in interact
    rv = fun(data)
  File "/usr/lib/python2.7/site-packages/wdb/ui.py", line 545, in do_complete
    completion = loads(data)
  File "/usr/lib64/python2.7/json/__init__.py", line 338, in loads
    return _default_decoder.decode(s)
  File "/usr/lib64/python2.7/json/decoder.py", line 365, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib64/python2.7/json/decoder.py", line 383, in raw_decode
    raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

Chrome's predictive loading breaks wdb on some pages

I've noticed on one of my larger projects that if Chrome's predictive loading is enabled and the page is loaded predictively, wdb will hang trying to connect. I've had trouble creating a smaller test case (it's not all predictively loaded pages), and I assume it's some kind of timing thing. The page will debug fine when it's not predictively loaded.

To enable / disable predictive loading (it's enabled by default):

  1. Menu
  2. Settings
  3. Show advanced settings
  4. Predict network actions to improve page load performance)

Autostart Wdb server

Would be great an option to autostart the Wdb server if it is not found, for even quicker local debugging.

python -m wdb <file> appears broken under python2.6/osx w/ wdb 1.0.3

I can't seem to get -m wdb to work on python2.6/osx, even with a fresh pip install.

$ python2.6 -m wdb test.py 
/usr/bin/python2.6: wdb is a package and cannot be directly executed

wdb version:

$ pip show wdb

---
Name: wdb
Version: 1.0.3
Location: /Library/Python/2.6/site-packages
Requires: tornado, log-colorizer, jedi

ValueError: No JSON object could be decoded

Traceback (most recent call last):
  File "/home/mic4ael/PythonEnvs/indico/lib/python2.7/site-packages/wdb/ui.py", line 171, in loop
    stop = self.interact()
  File "/home/mic4ael/PythonEnvs/indico/lib/python2.7/site-packages/wdb/ui.py", line 208, in interact
    rv = fun(data)
  File "/home/mic4ael/PythonEnvs/indico/lib/python2.7/site-packages/wdb/ui.py", line 545, in do_complete
    completion = loads(data)
  File "/usr/lib64/python2.7/json/__init__.py", line 338, in loads
    return _default_decoder.decode(s)
  File "/usr/lib64/python2.7/json/decoder.py", line 366, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib64/python2.7/json/decoder.py", line 384, in raw_decode
    raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

AttributeError: 'str' object has no attribute 'set_next'

I ignore what caused this, but here is the auto-report.

Traceback (most recent call last):
  File "C:\Documents and Settings\yajo\Escritorio\qtmpy-env\lib\site-packages\wdb\ui.py", line 115, in loop
    stop = self.interact()
  File "C:\Documents and Settings\yajo\Escritorio\qtmpy-env\lib\site-packages\wdb\ui.py", line 155, in interact
    return fun(data)
  File "C:\Documents and Settings\yajo\Escritorio\qtmpy-env\lib\site-packages\wdb\ui.py", line 414, in do_complete
    fun = script.get_in_function_call()
  File "C:\Documents and Settings\yajo\Escritorio\qtmpy-env\lib\site-packages\jedi\api.py", line 254, in get_in_function_call
    return self.function_definition()
  File "C:\Documents and Settings\yajo\Escritorio\qtmpy-env\lib\site-packages\jedi\api.py", line 263, in function_definition
    sig = self.call_signatures()
  File "C:\Documents and Settings\yajo\Escritorio\qtmpy-env\lib\site-packages\jedi\api_classes.py", line 44, in wrapper
    result = func(*args, **kwds)
  File "C:\Documents and Settings\yajo\Escritorio\qtmpy-env\lib\site-packages\jedi\api.py", line 448, in call_signatures
    call, index = self._func_call_and_param_index()
  File "C:\Documents and Settings\yajo\Escritorio\qtmpy-env\lib\site-packages\jedi\api.py", line 467, in _func_call_and_param_index
    user_stmt, self.pos)
  File "C:\Documents and Settings\yajo\Escritorio\qtmpy-env\lib\site-packages\jedi\helpers.py", line 120, in search_function_definition
    arr, index = array_for_pos(stmt, pos, [pr.Array.TUPLE, pr.Array.NOARRAY])
  File "C:\Documents and Settings\yajo\Escritorio\qtmpy-env\lib\site-packages\jedi\helpers.py", line 108, in array_for_pos
    arr, index = search_call(command, pos)
  File "C:\Documents and Settings\yajo\Escritorio\qtmpy-env\lib\site-packages\jedi\helpers.py", line 95, in search_call
    arr, index = search_call(call.next, pos)
  File "C:\Documents and Settings\yajo\Escritorio\qtmpy-env\lib\site-packages\jedi\helpers.py", line 95, in search_call
    arr, index = search_call(call.next, pos)
  File "C:\Documents and Settings\yajo\Escritorio\qtmpy-env\lib\site-packages\jedi\helpers.py", line 97, in search_call
    arr, index = search_array(call.execution, pos)
  File "C:\Documents and Settings\yajo\Escritorio\qtmpy-env\lib\site-packages\jedi\helpers.py", line 78, in search_array
    new_arr, index = array_for_pos(stmt, pos, array_types)
  File "C:\Documents and Settings\yajo\Escritorio\qtmpy-env\lib\site-packages\jedi\helpers.py", line 103, in array_for_pos
    for command in stmt.get_commands():
  File "C:\Documents and Settings\yajo\Escritorio\qtmpy-env\lib\site-packages\jedi\parsing_representation.py", line 839, in get_commands
    result = self._parse_statement()
  File "C:\Documents and Settings\yajo\Escritorio\qtmpy-env\lib\site-packages\jedi\parsing_representation.py", line 1060, in _parse_statement
    result[-1].set_next(call)
AttributeError: 'str' object has no attribute 'set_next'

Watcher

It would be upper cool to have a watcher for a variable.

Requirements need versions

$ pip install wdb.server
# snip

$ wdb.server.py
Traceback (most recent call last):
  File "/home/bgraham/.virtualenv/server/bin/wdb.server.py", line 2, in <module>
    from wdb_server import server
  File "/home/bgraham/.virtualenv/server/lib/python2.7/site-packages/wdb_server/__init__.py", line 25, in <module>
    from wdb_server.state import (
  File "/home/bgraham/.virtualenv/server/lib/python2.7/site-packages/wdb_server/state.py", line 18, in <module>
    from tornado.util import unicode_type
ImportError: cannot import name unicode_type

I happened to have Tornado 2.4.1 installed already. Installing the latest (3.2.1 as I'm writing this) corrects the problem.

Looking back at the install output for wdb.server, log-colorizer and jedi were both already installed in my virtualenv and have no particular version required by wdb. There may be similar problems hiding here.

Make wdb easier to run on Windows

I'm developing on a Windows machine, and I have associated .py files with my text editor of choice, as opposed to the Python interpreter. This makes it difficult for me to run the wdb server from the command line, even though the directory where wdb.server.py is on my system path: if I type out just wdb.server.py, I only open it in my IDE; and if I put python in front of that, the shell can't find that file so I need to copy the entire path to it.

Proposed solution: add a .exe version of wdb.server.py for Windows installations, as is customary with many tools such as pip, Nose or Fabric.

"Got send for uuid ..." spam

Since I reinstalled everything in my machine I've started getting really verbose output from wdb server. Everything starting with:

_Got send for uuid dc03d341-0cbb-448d-a71d-e80399bf26a5 data Start

For example, this is what I was getting before when closing the tab with wdb.

[W 151126 10:46:11 state:93] Websocket is closed

But now, I get this.

Got send for uuid dc03d341-0cbb-448d-a71d-e80399bf26a5 data Close
Got send for uuid dc03d341-0cbb-448d-a71d-e80399bf26a5 data Die
[W 151126 10:46:11 state:93] Websocket is closed

But that is not the worst. Every single keystroke produces output. An example of what I get simply by reaching a wdb.set_trace() in the code.

Got send for uuid dc03d341-0cbb-448d-a71d-e80399bf26a5 data []
Got send for uuid dc03d341-0cbb-448d-a71d-e80399bf26a5 data Start
Got send for uuid dc03d341-0cbb-448d-a71d-e80399bf26a5 data Init|{"breaks": [], "cwd": "/home/omegak/Code/indico", "version": "2.1.8"}
Got send for uuid dc03d341-0cbb-448d-a71d-e80399bf26a5 data Title|{"subtitle": "Stepping", "title": "Wdb"}
Got send for uuid dc03d341-0cbb-448d-a71d-e80399bf26a5 data Trace|{"trace": [{"code": "self.__bootstrap_inner()", "current": false, "file": "/home/omegak/.linuxbrew/Cellar/python/2.7.10_2/lib/python2.7/threading.py", "flno": 769, "function": "__bootstrap", "level": 0, "llno": 787, "lno": 783}, {"code": "self.run()", "current": false, "file": "/home/omegak/.linuxbrew/Cellar/python/2.7.10_2/lib/python2.7/threading.py", "flno": 792, "function": "__bootstrap_inner", "level": 1, "llno": 864, "lno": 810}, {"code": "self.__target(*self.__args, **self.__kwargs)", "current": false, "file": "/home/omegak/.linuxbrew/Cellar/python/2.7.10_2/lib/python2.7/threading.py", "flno": 752, "function": "run", "level": 2, "llno": 767, "lno": 763}, {"code": "self.finish_request(request, client_address)", "current": false, "file": "/home/omegak/.linuxbrew/Cellar/python/2.7.10_2/lib/python2.7/SocketServer.py", "flno": 592, "function": "process_request_thread", "level": 3, "llno": 603, "lno": 599}, {"code": "self.RequestHandlerClass(request, client_address, self)", "current": false, "file": "/home/omegak/.linuxbrew/Cellar/python/2.7.10_2/lib/python2.7/SocketServer.py", "flno": 332, "function": "finish_request", "level": 4, "llno": 334, "lno": 334}, {"code": "self.handle()", "current": false, "file": "/home/omegak/.linuxbrew/Cellar/python/2.7.10_2/lib/python2.7/SocketServer.py", "flno": 649, "function": "__init__", "level": 5, "llno": 657, "lno": 655}, {"code": "rv = BaseHTTPRequestHandler.handle(self)", "current": false, "file": "/home/omegak/.virtualenvs/indico/lib/python2.7/site-packages/werkzeug/serving.py", "flno": 213, "function": "handle", "level": 6, "llno": 225, "lno": 217}, {"code": "self.handle_one_request()", "current": false, "file": "/home/omegak/.linuxbrew/Cellar/python/2.7.10_2/lib/python2.7/BaseHTTPServer.py", "flno": 336, "function": "handle", "level": 7, "llno": 342, "lno": 340}, {"code": "return self.run_wsgi()", "current": false, "file": "/home/omegak/.virtualenvs/indico/lib/python2.7/site-packages/werkzeug/serving.py", "flno": 246, "function": "handle_one_request", "level": 8, "llno": 252, "lno": 252}, {"code": "execute(self.server.app)", "current": false, "file": "/home/omegak/.virtualenvs/indico/lib/python2.7/site-packages/werkzeug/serving.py", "flno": 134, "function": "run_wsgi", "level": 9, "llno": 211, "lno": 194}, {"code": "for data in application_iter:", "current": false, "file": "/home/omegak/.virtualenvs/indico/lib/python2.7/site-packages/werkzeug/serving.py", "flno": 181, "function": "execute", "level": 10, "llno": 191, "lno": 184}, {"code": "app_iter = self.app(environ, start_response)", "current": false, "file": "/home/omegak/.virtualenvs/indico/lib/python2.7/site-packages/werkzeug/debug/__init__.py", "flno": 195, "function": "debug_application", "level": 11, "llno": 237, "lno": 199}, {"code": "return self.wsgi_app(environ, start_response)", "current": false, "file": "/home/omegak/.virtualenvs/indico/lib/python2.7/site-packages/flask/app.py", "flno": 1834, "function": "__call__", "level": 12, "llno": 1836, "lno": 1836}, {"code": "return self.app(environ, start_response)", "current": false, "file": "/home/omegak/.virtualenvs/indico/lib/python2.7/site-packages/werkzeug/wsgi.py", "flno": 575, "function": "__call__", "level": 13, "llno": 627, "lno": 599}, {"code": "response = self.full_dispatch_request()", "current": false, "file": "/home/omegak/.virtualenvs/indico/lib/python2.7/site-packages/flask/app.py", "flno": 1787, "function": "wsgi_app", "level": 14, "llno": 1825, "lno": 1817}, {"code": "rv = self.dispatch_request()", "current": false, "file": "/home/omegak/.virtualenvs/indico/lib/python2.7/site-packages/flask/app.py", "flno": 1463, "function": "full_dispatch_request", "level": 15, "llno": 1481, "lno": 1475}, {"code": "return self.view_functions[rule.endpoint](**req.view_args)", "current": false, "file": "/home/omegak/.virtualenvs/indico/lib/python2.7/site-packages/flask/app.py", "flno": 1441, "function": "dispatch_request", "level": 16, "llno": 1461, "lno": 1461}, {"code": "return obj().process(params)", "current": false, "file": "/home/omegak/Code/indico/indico/web/flask/util.py", "flno": 121, "function": "wrapper", "level": 17, "llno": 124, "lno": 124}, {"code": "profile_name, res = self._process_retry(params, i, profile, forced_conflicts)", "current": false, "file": "/home/omegak/Code/indico/MaKaC/webinterface/rh/base.py", "flno": 649, "function": "process"
, "level": 18, "llno": 751, "lno": 686}, {"code": "return self._process_retry_do(profile)", "current": false, "file": "/home/omegak/Code/indico/MaKaC/webinterface/rh/base.py", "flno": 627, "function": "_process_retry", "level": 19, "llno": 631, "lno": 631}, {"code": "res = self._process()", "current": false, "file": "/home/omegak/Code/indico/MaKaC/webinterface/rh/base.py", "flno": 581, "function": "_process_retry_do", "level": 20, "llno": 625, "lno": 624}, {"code": "regforms = self.event_new.registration_forms.filter(~RegistrationForm.is_deleted)", "current": true, "file": "/home/omegak/Code/indico/indico/modules/events/registra
tion/controllers/display.py", "flno": 83, "function": "_process", "level": 21, "llno": 97, "lno": 85}]}
Got send for uuid dc03d341-0cbb-448d-a71d-e80399bf26a5 data SelectCheck|{"frame": {"code": "regforms = self.event_new.registration_forms.filter(~RegistrationForm.is_deleted)", "current": true, "file": "/home/omegak/Code/indico/indico/modules/events/registration/controllers/display.py", "flno": 83, "function": "_proce
ss", "level": 21, "llno": 97, "lno": 85}, "name": "/home/omegak/Code/indico/indico/modules/events/registration/controllers/display.py"}
Got send for uuid dc03d341-0cbb-448d-a71d-e80399bf26a5 data Watched|{}
Got send for uuid dc03d341-0cbb-448d-a71d-e80399bf26a5 data File|/home/omegak/Code/indico/indico/modules/events/registration/controllers/display.py
Got send for uuid dc03d341-0cbb-448d-a71d-e80399bf26a5 data Select|{"file": "# This file is part of Indico.\n# Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).\n#\n# Indico is free software; you can redistribute it and/or\n# modify it under the terms of the GNU General Public License as\n# published by the Free Software Foundation; either version 3 of the\n# License, or (at your option) any later version.\n#\n# Indico is distributed in the hope that it will be useful, but\n# WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with Indico; if not, see <http://www.gnu.org/licenses/>.\n\nfrom __future__ import unicode_literals\n\nfrom uuid import UUID\n\nfrom flask import request, session, redirect, flash, jsonify\nfrom werkzeug.exceptions import Forbidden, NotFound\n\nfrom indico.core.db import db\nfrom indico.modules.auth.util import redirect_to_login\nfrom indico.modules.events.registration.controllers import RegistrationEditMixin, RegistrationFormMixin\nfrom indico.modules.events.registration.models.forms import RegistrationForm\nfrom indico.modules.events.registration.models.invitations import RegistrationInvitation, InvitationState\nfrom indico.modules.events.registration.models.items import PersonalDataType\nfrom indico.modules.events.registration.models.registrations import Registration\nfrom indico.modules.events.registration.util import (get_event_section_data, make_registration_form,\n                                                     create_registration, check_registration_email)\nfrom indico.modules.events.registration.views import (WPDisplayRegistrationFormConference,\n                                                      WPDisplayRegistrationFormMeeting,\n                                                      WPDisplayRegistrationFormLecture,\n                                                      WPDisplayRegistrationParticipantList)\nfrom indico.modules.events.payment import event_settings as payment_event_settings\nfrom indico.util.i18n import _\nfrom indico.web.flask.util import url_for\nfrom MaKaC.webinterface.rh.conferenceDisplay import RHConferenceBaseDisplay\n\n\nclass RHRegistrationFormDisplayBase(RHConferenceBaseDisplay):\n    CSRF_ENABLED = True\n\n    def _checkParams(self, params):\n        RHConferenceBaseDisplay._checkParams(self, params)\n        self.event = self._conf\n\n    @property\n    def view_class(self):\n        mapping = {\n            'conference': WPDisplayRegistrationFormConference,\n            'meeting': WPDisplayRegistrationFormMeeting,\n            'simple_event': WPDisplayRegistrationFormLecture\n        }\n        return mapping[self.event.getType()]\n\n\nclass RHRegistrationFormBase(RegistrationFormMixin, RHRegistrationFormDisplayBase):\n    def _checkParams(self, params):\n        RHRegistrationFormDisplayBase._checkParams(self, params)\n        RegistrationFormMixin._checkParams(self)\n\n\nclass RHRegistrationFormRegistrationBase(RHRegistrationFormBase):\n    \"\"\"Base for RHs handling individual registrations\"\"\"\n\n    def _checkParams(self, params):\n        RHRegistrationFormBase._checkParams(self, params)\n        self.token = request.args.get('token')\n        if self.token:\n            self.registration = self.regform.get_registration(uuid=self.token)\n            if not self.registration:\n                raise NotFound\n        else:\n            self.registration = self.regform.get_registration(user=session.user) if session.user else None\n\n\nclass RHRegistrationFormList(RHRegistrationFormDisplayBase):\n    \"\"\"List of all registration forms in the event\"\"\"\n\n    def _process(self):\n        import wdb; wdb.set_trace()\n        regforms = self.event_new.registration_forms.filter(~RegistrationForm.is_deleted)\n        if session.user:\n            criteria = db.or_(\n                RegistrationForm.is_scheduled,\n                RegistrationForm.registrations.any((Registration.user == session.user) & Registration.is_active),\n            )\n        else:\n            criteria = RegistrationForm.is_scheduled\n        regforms = regforms.filter(criteria).order_by(db.func.lower(RegistrationForm.title)).all()\n        if len(regforms) == 1:\n            return redirect(url_for('.display_regform', regforms[0]))\n        return self.view_class.render_template('display/regform_list.html', self.event, event=self.event,\n                                               regforms=regforms)\n\n\nclass RHParticipantList(RHRegistrationFormDisplayBase):\n    \"\"\"List of all public registrations\"\"\"\n\n    view_class = WPDisplayRegistrationParticipantList\n\n    def _process(self):\n        regforms = RegistrationForm.find_all(RegistrationForm.publish_registrations_enabled,\n                                             event_id=int(self.event.id))\n        query = (Registration\n                 .find(Registration.event_id == self.event.id,\n                       RegistrationForm.publish_registrations_enabled,\n                       ~RegistrationForm.is_deleted,\n                       ~Registration.is_deleted,\n                       _join=Registration.registration_form)\n                 .order_by(db.func.lower(Registration.last_name), db.func.lower(Registration.first_name)))\n        registrations = [(reg.get_full_name(), reg.get_personal_data()) for reg in query]\n        return self.view_class.render_template(\n            'display/participant_list.html',\n            self.event,\n            event=self.event,\n            regforms=regforms,\n            show_affiliation=any(pd.get('affiliation') for reg, pd in registrations),\n            show_position=any(pd.get('position') for reg, pd in registrations),\n            registrations=registrations\n        )\n\n\nclass InvitationMixin:\n    \"\"\"Mixin for RHs that accept an invitation token\"\"\"\n\n    def _checkParams(self):\n        self.invitation = None\n        try:\n            token = request.args['invitation']\n        except KeyError:\n            return\n        try:\n            UUID(hex=token)\n        except ValueError:\n            flash(_(\"Your invitation code is not valid.\"), 'warning')\n            return\n        self.invitation = RegistrationInvitation.find(uuid=token).with_parent(self.regform).first()\n        if self.invitation is None:\n            flash(_(\"This invitation does not exist or has been withdrawn.\"), 'warning')\n\n\nclass RHRegistrationFormCheckEmail(RHRegistrationFormBase):\n    \"\"\"Checks how an email will affect the registration\"\"\"\n\n    def _process(self):\n        email = request.args['email'].lower().strip()\n        update = request.args.get('update')\n        management = request.args.get('management') == '1'\n\n        if update:\n            existing = self.regform.get_registration(uuid=update)\n            return jsonify(check_registration_email(self.regform, email, existing, management=management))\n        else:\n            return jsonify(check_registration_email(self.regform, email, management=management))\n\n\nclass RHRegistrationForm(InvitationMixin, RHRegistrationFormRegistrationBase):\n    \"\"\"Display a registration form and registrations, and process submissions\"\"\"\n\n    normalize_url_spec = {\n        'locators': {\n            lambda self: self.regform\n        }\n    }\n\n    def _checkProtection(self):\n        RHRegistrationFormRegistrationBase._checkProtection(self)\n        if self.regform.require_login and not session.user and request.method != 'GET':\n            raise Forbidden(response=redirect_to_login(reason=_('You are trying to register with a form '\n                                                                'that requires you to be logged in')))\n\n    def _checkParams(self, params):\n        RHRegistrationFormRegistrationBase._checkParams(self, params)\n        InvitationMixin._checkParams(self)\n        if self.invitation and self.invitation.state == InvitationState.accepted and self.invitation.registration:\n            return redirect(url_for('.display_regform', self.invitation.registration.locator.registrant))\n\n    def _process(self):\n        form = make_registration_form(self.regform)()\n        if form.validate_on_submit():\n            registration = create_registration(self.regform, form.data, self.invitation)\n            return redirect(url_for('.display_regform', registration.locator.registrant))\n        elif form.is_submitted():\n            # not very pretty but usually this never happens thanks to client-side validation\n            for error in form.error_list:\n                flash(error, 'error')\n\n        user_data = {t.name: getattr(session.user, t.name, None) if session.user else '' for t in PersonalDataType}\n        if self.invitation:\n            user_data.update((attr, getattr(self.invitation, attr)) for attr in ('first_name', 'last_name', 'email'))\n        return self.view_class.render_template('display/regform_display.html', self.event, event=self.event,\n                                               sections=get_event_section_data(self.regform), regform=self.regform,\n                                               payment_conditions=payment_event_settings.get(self.event, 'conditions'),\n                                               payment_enabled=self.event.has_feature('payment'),\n                                               user_data=user_data, invitation=self.invitation,\n                                               registration=self.registration,\n                                               login_required=self.regform.require_login and not session.user)\n\n\nclass RHRegistrationDisplayEdit(RegistrationEditMixin, RHRegistrationFormRegistrationBase):\n    \"\"\"Submit a registration form\"\"\"\n\n    template_file = 'display/registration_modify.html'\n    management = False\n\n    def _checkParams(self, params):\n        RHRegistrationFormRegistrationBase._checkParams(self, params)\n        if self.registration is None:\n            if session.user:\n                flash(_(\"We could not find a registration for you.  If have already registered, please use the \"\n                        \"direct access link from the email you received after registering.\"), 'warning')\n            else:\n                flash(_(\"We could not find a registration for you.  If have already registered, please use the \"\n                        \"direct access link from the email you received after registering or log in to your Indico \"\n                        \"account.\"), 'warning')\n            return redirect(url_for('.display_regform', self.regform))\n\n    @property\n    def success_url(self):\n        return url_for('.display_regform', self.registration.locator.registrant)\n\n\nclass RHRegistrationFormDeclineInvitation(InvitationMixin, RHRegistrationFormBase):\n    \"\"\"Decline an invitation to register\"\"\"\n\n    def _checkParams(self, params):\
n        RHRegistrationFormBase._checkParams(self, params)\n        InvitationMixin._checkParams(self)\n\n    def _process(self):\n        if self.invitation.state == InvitationState.pending:\n            self.invitation.state = InvitationState.declined\n            flash(_(\"You declined the invitation to register.\
"))\n        return redirect(url_for('event.conferenceDisplay', self.event))\n", "frame": {"code": "regforms = self.event_new.registration_forms.filter(~RegistrationForm.is_deleted)", "current": true, "file": "/home/omegak/Code/indico/indico/modules/events/registration/controllers/display.py", "flno": 83, "function":
 "_process", "level": 21, "llno": 97, "lno": 85}, "name": "/home/omegak/Code/indico/indico/modules/events/registration/controllers/display.py"}

This happens with wdb.server==2.1.8 only.

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 21: ordinal not in range(128)

I got this when I middle clicked to evaluate a queryset featuring model instances containing the '£' symbol, in the string returned by the unicode method. Unless it's to do with the arrow character used in the formatted string? Might just be a case of a missing file encoding.

Traceback (most recent call last):
  File "/home/mk/.virtualenvs/fm/local/lib/python2.7/site-packages/wdb/ui.py", line 155, in loop
    stop = self.interact()
  File "/home/mk/.virtualenvs/fm/local/lib/python2.7/site-packages/wdb/ui.py", line 192, in interact
    rv = fun(data)
  File "/home/mk/.virtualenvs/fm/local/lib/python2.7/site-packages/wdb/ui.py", line 276, in do_dump
    'for': u('%s ⟶ %s ') % (data, repr(thing)),
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 21: ordinal not in range(128)

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 2658: ordinal not in range(128)

Traceback (most recent call last):
  File "/opt/virtualenvs/production/local/lib/python2.7/site-packages/wdb/ui.py", line 162, in loop
    stop = self.interact()
  File "/opt/virtualenvs/production/local/lib/python2.7/site-packages/wdb/ui.py", line 199, in interact
    rv = fun(data)
  File "/opt/virtualenvs/production/local/lib/python2.7/site-packages/wdb/ui.py", line 505, in do_complete
    '\n'.join(reversed(segments))))
  File "/opt/virtualenvs/production/local/lib/python2.7/site-packages/wdb/ui.py", line 219, in notify_exc
    'message': '%s\n%s' % (msg, traceback.format_exc())
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 2658: ordinal not in range(128)

debugger (web-frontend) does not react to key-strokes

Hi,

First of all - thank you for writing such a nice tool and sharing it!
I am using Chrome 33.0.1750.152 on MacOSX 10.9.2 and cannot use the following keyboard commands in the web-frontend.

[Ctrl] + [↓] or [F11]    : Step into
[Ctrl] + [→] or [F10]    : Step over (Next)
[Ctrl] + [↑] or [F9]     : Step out (Return)
[Ctrl] + [←] or [F8]     : Continue

The equivalent shell-commands (e.g. .s etc) work, but not the function keys.
I hope I am not doing something potentially wrong, but even in this case the documentation might need an update.

Thanks,
Marco

BrokenPipeError error

Can't give you exact repro steps, but this happens surprisingly frequently on my machine:

  File "/usr/local/lib/python2.7/dist-packages/wdb/__init__.py", line 263, in trace_dispatch
    fun(frame, arg)
  File "/usr/local/lib/python2.7/dist-packages/wdb/__init__.py", line 729, in handle_line
    self.interaction(frame)
  File "/usr/local/lib/python2.7/dist-packages/wdb/__init__.py", line 691, in interaction
    self.reconnect_if_needed()
  File "/usr/local/lib/python2.7/dist-packages/wdb/__init__.py", line 181, in reconnect_if_needed
    except BrokenPipeError:
NameError: global name 'BrokenPipeError' is not defined

Should the code be looking for IOError there instead?

Broken UI layout in Firefox

Good layout in Epiphany 3.14.2 (webkit):

captura de pantalla de 2015-03-17 13 53 55

Bad layout in Firefox 35:

captura de pantalla de 2015-03-17 13 52 39

As you can see there:

  • The blue header bar overlaps some UI elements.
  • The div#interpreter is at the bottom (it's not in the screenshot, you have to scroll down a lot to see it).

Resizing the Epiphany window works very well and adjusts the layout to the most comfortable size. Would be nice to have that in Firefox, and I guess it's not very hard.

.cerror: [Errno 4] Interrupted system call

Traceback (most recent call last):
  File "/home/nchunduru/projects/HearsayLabs/.virtualenv/local/lib/python2.7/site-packages/wdb/ui.py", line 162, in loop
    stop = self.interact()
  File "/home/nchunduru/projects/HearsayLabs/.virtualenv/local/lib/python2.7/site-packages/wdb/ui.py", line 189, in interact
    message = self.db.receive()
  File "/home/nchunduru/projects/HearsayLabs/.virtualenv/local/lib/python2.7/site-packages/wdb/__init__.py", line 576, in receive
    data = self._socket.recv_bytes()
  File "/home/nchunduru/projects/HearsayLabs/.virtualenv/local/lib/python2.7/site-packages/wdb/_compat.py", line 135, in recv_bytes
    size, = struct.unpack("!i", self._handle.recv(4))
error: [Errno 4] Interrupted system call

error: [Errno 4] Interrupted system call

I just pressed F10 while debugging.

Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/wdb/ui.py", line 162, in loop
    stop = self.interact()
  File "/usr/lib/python2.7/site-packages/wdb/ui.py", line 189, in interact
    message = self.db.receive()
  File "/usr/lib/python2.7/site-packages/wdb/__init__.py", line 634, in receive
    data = self._socket.recv_bytes()
  File "/usr/lib/python2.7/site-packages/wdb/_compat.py", line 142, in recv_bytes
    size, = struct.unpack("!i", self._handle.recv(4))
error: [Errno 4] Interrupted system call

Not working

I've been unable to get the test (python -m wdb.test) or my own test app to work. Accessing either http://localhost:1984 or ``http://localhost:1984/wtf` will show "Wdb is tracing your request. It may take some time......" and continue to append periods, but never proceeds (I've waiting up to 10 minutes). Here's a screenshot - http://imgur.com/qQg9zwa

AttributeError: 'module' object has no attribute '__code__'

While debugging, I wrote something like .b module.name#function.

Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/wdb/ui.py", line 162, in loop
    stop = self.interact()
  File "/usr/lib/python2.7/site-packages/wdb/ui.py", line 199, in interact
    rv = fun(data)
  File "/usr/lib/python2.7/site-packages/wdb/ui.py", line 461, in do_break
    brk['fn'], brk['lno'], brk['temporary'], brk['cond'], brk['fun'])
  File "/usr/lib/python2.7/site-packages/wdb/__init__.py", line 392, in set_break
    filename, lineno, temporary, cond, funcname)
  File "/usr/lib/python2.7/site-packages/wdb/__init__.py", line 382, in get_break
    return FunctionBreakpoint(filename, funcname, temporary)
  File "/usr/lib/python2.7/site-packages/wdb/breakpoint.py", line 128, in __init__
    file = file_from_import(file, function)
  File "/usr/lib/python2.7/site-packages/wdb/breakpoint.py", line 28, in file_from_import
    return fun.__code__.co_filename
AttributeError: 'module' object has no attribute '__code__'

WebSocket is not defined: Page stays at "WDB is tracing your request.It may take some time" forever

Hi,
I was trying out wdb for my python scripts and followed the steps mentioned in https://github.com/Kozea/wdb

Steps followed:

  1. pip install wdb
  2. pip install flask
    python -m wdb.test

Environment:
Ubuntu 11.0.4 - Linux
Browser - Mozilla Firefox
WDB version - wdb-0.9.3

Issue:

  1. Upon accessing http://localhost:1984/, Page stays at "WDB is tracing your request.It may take some time" forever
  2. Upon accessing http://localhost:1984/wtf, I get following errors on browser's console

Errors on Browser console:

  1. Error: WebSocket is not defined
    Source File: http://localhost:1984/__wdb/wdb.js
    Line: 150
  2. Error: uncaught exception: [Exception... "The operation failed because the requested database object could not be found. For example, an object store did not exist but was being opened." code: "3" nsresult: "0x80660003 (NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR)" location: "http://localhost:1984/__wdb/wdb.js Line: 122"]
  3. Error: uncaught exception: ReferenceError: WebSocket is not defined

Please let me know if anything else is required here for it to work

wdb client under IronPython

Hi, I've been trying to make wdb run under IronPython (2.7.6a0), and after a recent breakthrough I can now run the wdb server in Python and step through IronPython code with wdb client - https://github.com/kerray/wdb/commit/72019a080df8252c663e8e630d4fd104976ceff8

The main problem I sidestepped was that dis.findlinestarts() is not supported in IronPython - but there's something else going on (maybe also because of my sidestepping 'hack').

While I can step through code (and inspect variables etc), when I put a wdb.set_trace() in baseline module code, it only activates when I call a function from my module code. Wdb correctly steps through the execution of that function, but after exiting that function the next step will not be back in the module code, but only into another called function, if there is one.

If not, that's another (and maybe connected) problem. When (under IronPython without dis.findlinestarts) the module I was trying to debug ends, the debugger continues on into IronPython threading code.

I'm not too skilled yet with developing debuggers, so I would be really glad for some ideas or pointers.

Thanks!

Server block

Sometimes the server blocks on waiting for a websocket connection while the javascript doesn't try to connect. Which leads to a blocked server.

TypeError: cannot concatenate 'str' and 'bool' objects

Clicking on a SQLAlchemy ORM record.

Traceback (most recent call last):
  File "/home/jllopis/Documentos/devel/odoo-tester/virtualenv/lib/python2.7/site-packages/wdb/ui.py", line 162, in loop
    stop = self.interact()
  File "/home/jllopis/Documentos/devel/odoo-tester/virtualenv/lib/python2.7/site-packages/wdb/ui.py", line 199, in interact
    rv = fun(data)
  File "/home/jllopis/Documentos/devel/odoo-tester/virtualenv/lib/python2.7/site-packages/wdb/ui.py", line 274, in do_inspect
    'val': self.db.dmp(thing),
  File "/home/jllopis/Documentos/devel/odoo-tester/virtualenv/lib/python2.7/site-packages/wdb/__init__.py", line 493, in dmp
    for key in dir(thing)
  File "/home/jllopis/Documentos/devel/odoo-tester/virtualenv/lib/python2.7/site-packages/wdb/__init__.py", line 493, in <genexpr>
    for key in dir(thing)
  File "/home/jllopis/Documentos/devel/odoo-tester/virtualenv/lib/python2.7/site-packages/wdb/__init__.py", line 392, in safe_better_repr
    escape(repr(obj)))
  File "/home/jllopis/Documentos/devel/odoo-tester/virtualenv/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1573, in __repr__
    return 'Engine(%r)' % self.url
  File "/home/jllopis/Documentos/devel/odoo-tester/virtualenv/lib/python2.7/site-packages/sqlalchemy/engine/url.py", line 93, in __repr__
    return self.__to_string__()
  File "/home/jllopis/Documentos/devel/odoo-tester/virtualenv/lib/python2.7/site-packages/sqlalchemy/engine/url.py", line 82, in __to_string__
    s += '/' + self.database
TypeError: cannot concatenate 'str' and 'bool' objects

Post Mortem debugging

Hi,

While trying to understand errors in large swathes of code I usually turn

function_that_call_large_swathes_of_code(some, params)

Into:

try:
    function_that_call_large_swathes_of_code(some, params)
except:
    import pdb; pdb.post_mortem()
    raise

This gives me a pdb prompt right in the point where an error was raised, allowing me to evaluate expressions in that frame and all frames above it.

If I use pdb.set_trace() instead of pdb.post_mortem(), I get an almost useless pdb prompt at the point where the error was caught instead of where the error was raised.

I wish there was a wdb.post_mortem() that worked like a pdb.post_mortem(), but there isn't, and calling wdb.set_trace() inside the except: clause has the same limited utility as pdb.set_trace().

By the way, I did try calling:

wdb.set_trace(sys.exc_info()[2].tb_frame)

As well as:

wdb.set_trace(sys.exc_info()[2].tb_next.tb_frame)

But all I got was the same as if I had called wdb.set_trace(). Probably because wdb is setting traces in all those traceback frames, but only the exception catching frame is alive and traceable, so it's the only one that gets traced.

Then it dawned on me that pdb.post_mortem() doesn't actually set any traces, it directly interacts with the exception traceback, so I managed to get the equivalent of pdb.post_mortem() with the following code:

import wdb
exc_info = sys.exc_info()
wdb.Wdb.get().handle_exception(frame=exc_info[2].tb_frame, exc_info=exc_info)

Since the above is a mouthful, it would be nice to have a wdb.post_mortem() that did the above, as well as a shortcut for it like w.tf is for wdb.set_trace().

Notice that pdb.Pdb.setup() (called indirectly by pdb.post_mortem()) does some dance with traceback.tb_frame and traceback.tb_next, to handle nested exceptions I think, and it might be necessary for wdb to do a similar dance.

Code completion not working

Just wondering if I'm missing some dependencies, it's a jedi problem, or the integration of wdb with jedi is working somewhat sloppy only for me. Does anybody else notice bad to completely nonexistent code completion?

Diff

Adding the possibility to diff variables would avoid the need to export the variables result in files and thus will improve productivity :)

pip install wdb.server broken

pip.log

/usr/bin/pip run on Sat May  3 06:05:32 2014
Downloading/unpacking wdb.server
  Getting page http://pypi.python.org/simple/wdb.server
  URLs to search for versions for wdb.server:
  * http://pypi.python.org/simple/wdb.server/
  Getting page http://pypi.python.org/simple/wdb.server/
  Analyzing links from page https://pypi.python.org/simple/wdb.server/
  Could not find any downloads that satisfy the requirement wdb.server
No distributions at all found for wdb.server

─>curl https://pypi.python.org/simple/wdb.server/

<html><head><title>Links for wdb.server</title><meta name="api-version" value="2" /></head><body><h1>Links for wdb.server</h1></body></html>%

Is pypi link for wdb.server broken?

In with_tornado function, the _wdb_execute need to be decorated by gen.coroutine

Example:
Just Define a handler:
class TestHandler(BaseHandler):
def get(self):
self.write("OK\n")
return
....
main.py:
app = application.Applicaiton()

from wdb.ext import wdb_tornado
wdb_tornado(app)
....

running like: python3 main.py # tornado Application, No wsgi wrap it.

tornado log:
Traceback (most recent call last):
File "/usr/lib/python3.4/site-packages/tornado/http1connection.py", line 236, in _read_message
delegate.finish()
File "/usr/lib/python3.4/site-packages/tornado/httpserver.py", line 269, in finish
self.delegate.finish()
File "/usr/lib/python3.4/site-packages/tornado/web.py", line 1898, in finish
self.execute()
File "/usr/lib/python3.4/site-packages/tornado/web.py", line 1930, in execute
f.add_done_callback(lambda f: f.exception())
AttributeError: 'NoneType' object has no attribute 'add_done_callback'

In function with_tornado:
def with_tornado():
...
from tornado import gen
...
# the _wdb_execute need to be decorated by gen.coroutine
RequestHandler._execute = gen.coroutine(_wdb_execute)
...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.