Dec 28, 2009

Add bpython to django's shell management command

Like many of us I am spending a lot of time in the REPL loop to develop django code and this bug in readline cost me an extra backspace each time  I hit "tab" in ipython.

This blog post capture my attention so I have decided to give bpython a try and so far I have been impressed by what I have seen. Here it is a management command that adds the support for bpython to django's shell management command.


import os
from django.core.management.base import NoArgsCommand
from optparse import make_option
from IPython.Shell import IPShell

def start_plain_shell():
    import code
    # Set up a dictionary to serve as the environment for the shell, so
    # that tab completion works on objects that are imported at runtime.
    # See ticket 5082.
    imported_objects = {}
    try: # Try activating rlcompleter, because it's handy.
        import readline
    except ImportError:
        pass
    else:
        # We don't have to wrap the following import in a 'try', because
        # we already know 'readline' was imported successfully.
        import rlcompleter
        readline.set_completer(rlcompleter.Completer(imported_objects).complete)
        readline.parse_and_bind("tab:complete")

    # We want to honor both $PYTHONSTARTUP and .pythonrc.py, so follow system
    # conventions and get $PYTHONSTARTUP first then import user.
    if not use_plain: 
        pythonrc = os.environ.get("PYTHONSTARTUP") 
        if pythonrc and os.path.isfile(pythonrc): 
            try: 
                execfile(pythonrc) 
            except NameError: 
                pass
        # This will import .pythonrc.py as a side-effect
        import user
    code.interact(local=imported_objects)

def start_ipython_shell():
    import IPython
    # Explicitly pass an empty list as arguments, because otherwise IPython
    # would use sys.argv from this script.
    shell = IPython.Shell.IPShell(argv=[])
    shell.mainloop()
    
def start_bpython_shell():
    from bpython import cli
    cli.main(args=[])
    

class Command(NoArgsCommand):
    option_list = NoArgsCommand.option_list + (
        make_option('--plain', action='store_true', dest='plain',
            help='Tells Django to use plain Python, not IPython.'),
        make_option('--ipython', action='store_true', dest='ipython',
            help='Tells Django to use ipython.'),
        make_option('--bpython', action='store_true', dest='bpython',
            help='Tells Django to use bpython.'),
    )
    help = "Runs a Python interactive interpreter. Tries to use IPython, if it's available."

    requires_model_validation = False

    def handle_noargs(self, **options):
        # XXX: (Temporary) workaround for ticket #1796: force early loading of all
        # models from installed apps.
        from django.db.models.loading import get_models
        loaded_models = get_models()

        use_plain = options.get('plain', False)
        use_ipython = options.get('ipython', False)
        use_bpython = options.get('bpython', False)
        
        try:
            if use_plain:
                # Don't bother loading IPython, because the user wants plain Python.
                raise ImportError
            elif use_ipython:
                start_ipython_shell()
            elif use_bpython:
                start_bpython_shell()
            else:
                # backward compatible behavior.
                start_ipython_shell()

        except ImportError:
            # fallback to plain shell if we encounter an ImportError
            start_plain_shell()

Is there an exiting debugger that use bpython ? I am looking for something equivalent to ipdb but for bpython. I am looking for something that could replace :


import ipdb; ipdb.set_trace()
blog comments powered by Disqus