Skip to content

Instantly share code, notes, and snippets.

@Quotation
Forked from defrex/shell.py
Last active August 19, 2023 14:23
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Quotation/909f87320b03b028d23c to your computer and use it in GitHub Desktop.
Save Quotation/909f87320b03b028d23c to your computer and use it in GitHub Desktop.
Use ptpython for Django shell
from django.core.management.commands.shell import Command as ShellCommand
import os
class Command(ShellCommand):
shells = ShellCommand.shells.append('ptpython')
def ptpython(self):
try:
# old ptpython
from prompt_toolkit.contrib.repl import embed
except ImportError:
# new ptpython
from ptpython.repl import embed
history_filename = os.path.expanduser('~/.ptpython_history')
embed(globals(), locals(), vi_mode=False, history_filename=history_filename)
@Quotation
Copy link
Author

Put shell.py into <any app>/management/commands/. Run

./manage.py shell -i ptpython

@pebreo
Copy link

pebreo commented Jan 13, 2017

Thanks for sharing. For me to get it to work it I had put __init__.py in the management and comands directory. Also my function looked like this:

    def ptpython(self):
        from ptpython.repl import embed
        embed(globals(), locals(), vi_mode=False)

@Quotation
Copy link
Author

Updated the code to be compatible with both old and new version of ptpython. Thanks @pebreo.

@doconix
Copy link

doconix commented Nov 29, 2017

Thanks for the code. One improvement: If you add configure=run_config to the embed call, it enables the standard ~/.ptpython/config.py file.

(also change import to from ptpython.repl import embed, run_config)

@trpx
Copy link

trpx commented Jul 16, 2019

I looked in the Command source (my Django version is 2.2),
it defines a handy class attr shells = ['ipython', 'bpython', 'python']
which contains the list of methods similar to the ptpython method
provided by the above authors, when you run ./manage.py shell
django tries these methods in the order they are listed in this shell attr
if the method fails with ImportError (i.e. there is no installed ptpython)
it tries the next and eventually falls back to simple python as you can see
in the shells list.

So following this Django builtin logic you can do the following:

# <any app>/management/commands/shell.py

def ptpython(self, options):
    ...

Command.ptpython = ptpython
Command.shells.insert(0, 'ptpython')

Then the command ./manage.py shell will start Django shell with ptpython
if the ptpython is installed.

These commands will still work too:

./manage.py shell -i ptpython
./manage.py shell -i ipython
./manage.py shell -i python

@yatmanov
Copy link

First of all thanks for the code, I've been using this for a long period of time. ptpython provides very convenient way of interactions with django apis. But unfortunately this does not work anymore, at least with Django version 2.2.6

For me ./manage.py shell -i ptpython command produces following traceback:

Traceback (most recent call last):
  ...
  File "C:\Users\yatmanov\AppData\Local\Programs\Python\Python37\lib\site-packages\django\core\management\__init__.py", line 381, in execute_from_command_line
    utility.execute()
  File "C:\Users\yatmanov\AppData\Local\Programs\Python\Python37\lib\site-packages\django\core\management\__init__.py", line 375, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "C:\Users\yatmanov\AppData\Local\Programs\Python\Python37\lib\site-packages\django\core\management\base.py", line 323, in run_from_argv
    self.execute(*args, **cmd_options)
  File "C:\Users\yatmanov\AppData\Local\Programs\Python\Python37\lib\site-packages\django\core\management\base.py", line 364, in execute
    output = self.handle(*args, **options)
  File "C:\Users\yatmanov\AppData\Local\Programs\Python\Python37\lib\site-packages\django\core\management\commands\shell.py", line 99, in handle
    return getattr(self, shell)(options)
TypeError: ptpython() takes 1 positional argument but 2 were given

So I searched for other solutions and found it on ptpython project's github page: https://github.com/prompt-toolkit/ptpython#django-support

All you need to do is install django-extensions alongside with ptpython, and add it to INSTALLED_APPS. After that you can prompt ptpython by next command:
python manage.py shell_plus

@michaelhays
Copy link

michaelhays commented Nov 13, 2019

If you get:

TypeError: ptpython() takes 1 positional argument but 2 were given

try changing

def ptpython(self):

to

def ptpython(self, options):

Here's my full management/commands/shell.py file:

import os

from django.core.management.commands.shell import Command
from ptpython.repl import embed


def ptpython(self, options):
    history_filename = os.path.expanduser("~/.ptpython_history")
    embed(globals(), locals(), vi_mode=False, history_filename=history_filename)


Command.ptpython = ptpython
Command.shells.insert(0, "ptpython")

@namper
Copy link

namper commented Sep 10, 2022

Append is incorrect should be ShellCommand.shells + ['ptpython']

Full version:

from django.core.management.commands.shell import Command as ShellCommand
import os


class Command(ShellCommand):
    shells = ShellCommand.shells + ['ptpython']

    def ptpython(self, options):
        from ptpython.repl import embed

        history_filename = os.path.expanduser('~/.ptpython_history')
        embed(globals(), locals(), vi_mode=False, history_filename=history_filename)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment