24

I use standard tips for customizing interactive Python session:

$ cat ~/.bashrc
export PYTHONSTARTUP=~/.pystartup

$ cat ~/.pystartup
import os
import sys
import atexit
import readline
import rlcompleter

historyPath = os.path.expanduser("~/.pyhistory")

def save_history(historyPath=historyPath):
    import readline
    readline.write_history_file(historyPath)

if os.path.exists(historyPath):
    readline.read_history_file(historyPath)

term_with_colors = ['xterm', 'xterm-color', 'xterm-256color', 'linux', 'screen', 'screen-256color', 'screen-bce']
if os.environ.get('TERM') in term_with_colors:
    green='\033[32m'
    red='\033[31m'
    reset='\033[0m'
    sys.ps1 = red + '>>> ' + reset
    sys.ps2 = green + '... ' + reset
del term_with_colors

atexit.register(save_history)
del os, sys, atexit, readline, rlcompleter, save_history, historyPath

Now I get context sensitive completion and color prompt.

The problem comes from color prompt - when I invoke history-search-backward (by pressing UP) in an interactive Python session, Readline takes in account terminal escape sequences, so the cursor position is wrongly calculated and the text is wrongly displayed.

In Bash man page this problem is mentioned and fixed by special markers:

    \[     begin a sequence of non-printing characters,
           which could be used to embed a
           terminal control sequence into the prompt
    \]     end a sequence of non-printing characters

How to fix this issue for Python prompt?

wjandrea
  • 28,235
  • 9
  • 60
  • 81
gavenkoa
  • 45,285
  • 19
  • 251
  • 303

3 Answers3

37

I open info readline and found:

 -- Function: int rl_expand_prompt (char *prompt)
     Expand any special character sequences in PROMPT and set up the
     local Readline prompt redisplay variables.  This function is
     called by `readline()'.  It may also be called to expand the
     primary prompt if the `rl_on_new_line_with_prompt()' function or
     `rl_already_prompted' variable is used.  It returns the number of
     visible characters on the last line of the (possibly multi-line)
     prompt.  Applications may indicate that the prompt contains
     characters that take up no physical screen space when displayed by
     bracketing a sequence of such characters with the special markers
     `RL_PROMPT_START_IGNORE' and `RL_PROMPT_END_IGNORE' (declared in
     `readline.h'.  This may be used to embed terminal-specific escape
     sequences in prompts.

As text suggested I searched for RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE definition in readline.h and found next:

/* Definitions available for use by readline clients. */
#define RL_PROMPT_START_IGNORE  '\001'
#define RL_PROMPT_END_IGNORE    '\002'

So I put appropriate changes to my ~/.pystartup:

    green='\001\033[32m\002'
    red='\001\033[31m\002'
    reset='\001\033[0m\002'

and now all work fine!!!

gavenkoa
  • 45,285
  • 19
  • 251
  • 303
  • The *readline* development sources can be found [here](http://git.savannah.gnu.org/cgit/readline.git/tree/). – not2qubit Feb 01 '22 at 11:25
6

For a better python shell experience, I'd recommend you to use either ipython or bpython.

jcollado
  • 39,419
  • 8
  • 102
  • 133
  • +1. bpython is great thing! How about django **./manage.py** console? My solution also enable completion in django interactive session, how to use bpython for this purpose? – gavenkoa Feb 27 '12 at 17:08
  • 2
    @gavenkoa Looking at [core.managment.commands.shell](https://code.djangoproject.com/browser/django/trunk/django/core/management/commands/shell.py), I see that if `ipython` fails, `bpython` is used. If you have both installed, you can still edit that file and reorder `shells` class attribute so that `bpython` is attempted before `ipython`. – jcollado Feb 27 '12 at 17:20
0

If you happen to come here because of recent Python 3.10+ REPL (CLI) problems in Win10, then please have a look here:

Some of these issues has now been fixed in a better maintained repo:

not2qubit
  • 14,531
  • 8
  • 95
  • 135