'How does django's `python manage.py shell` keep the command prompt open?

When you run python manage.py shell, (or shell_plus if you have the extension), the script will import some stuff for you and then open a regular python shell for you to try commands out, as opposed to running the script and immediately closing.

I know that you can use the -i switch when calling a script to keep the command prompt open, for example python -i foo.py will run the contents of foo.py yet keep the shell open instead of immediately closing.

I would guess that when you call django's manage.py shell it somehow uses the same feature to get the command prompt to stay open and not immediately close out.

How does it work? Can I add something to any script file to make it behave the same way (without using the -i switch) ?



Solution 1:[1]

As of 2.2.3, the shell management command has three programs it can start -- ipython, bpython, and python. For the first two, you can start the shells using python:

    def ipython(self, options):
        from IPython import start_ipython
        start_ipython(argv=[])

    def bpython(self, options):
        import bpython
        bpython.embed()

For python, django sets up readline and then uses code.interact to start the python interpreter:

    def python(self, options):
        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.
        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)
            # Enable tab completion on systems using libedit (e.g. macOS).
            # These lines are copied from Python's Lib/site.py.
            readline_doc = getattr(readline, '__doc__', '')
            if readline_doc is not None and 'libedit' in readline_doc:
                readline.parse_and_bind("bind ^I rl_complete")
            else:
                readline.parse_and_bind("tab:complete")

        # We want to honor both $PYTHONSTARTUP and .pythonrc.py, so follow system
        # conventions and get $PYTHONSTARTUP first then .pythonrc.py.
        if not options['no_startup']:
            for pythonrc in OrderedSet([os.environ.get("PYTHONSTARTUP"), os.path.expanduser('~/.pythonrc.py')]):
                if not pythonrc:
                    continue
                if not os.path.isfile(pythonrc):
                    continue
                with open(pythonrc) as handle:
                    pythonrc_code = handle.read()
                # Match the behavior of the cpython shell where an error in
                # PYTHONSTARTUP prints an exception and continues.
                try:
                    exec(compile(pythonrc_code, pythonrc, 'exec'), imported_objects)
                except Exception:
                    traceback.print_exc()

        code.interact(local=imported_objects)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 2ps