ipdb icon indicating copy to clipboard operation
ipdb copied to clipboard

How do we customize the color scheme for ipdb?

Open AdrienLemaire opened this issue 4 years ago • 10 comments

Related: #50, #144, #57, #1

By searching around, I understand (probably incorrectly) that ipdb should use ipython's color scheme by default. And that ipython use pygments styles.

So I tried the following:

  • ipython profile create
  • pygmentize -L style
  • vim profile_default/ipython_config
    c.TerminalInteractiveShell.highlighting_style = 'tomorrownight'
    

Within the same virtualenv, I get colors within ipython, but not within ipdb:

image

image

The prompt seems to be another matter, and I haven't figured out how to change its color yet.

Therefore, I have 2 related questions:

  • Why doesn't ipdb pick up the ipython pygment style? Else how can I override the ipdb shell colors?
  • How can I modify the ipdb prompt color?

Thanks for your help in advance!

AdrienLemaire avatar Jan 21 '20 06:01 AdrienLemaire

I have never tried to customize IPython or ipdb colors myself.

I am sorry I cannot help and hope you'll report here if you succeeds.

gotcha avatar Jan 21 '20 14:01 gotcha

Investigating the Prompt color issue

I can modify the prompt text in IPython/core/debugger.py

prompt = 'ipdb> '

I can modify the prompt color in IPython/terminal/interactiveshell.py

class TerminalInteractiveShell(InteractiveShell):
    def _make_style_from_name_or_cls(self, name_or_cls):
        if name_or_cls == 'legacy':
        else :
            if isinstance(name_or_cls, str):
                style_cls = get_style_by_name(name_or_cls)
            else:
                style_cls = name_or_cls
            style_overrides = {
                Token.Prompt: '#009900',  # <-- OUR GREEN
                Token.PromptNum: '#ansibrightgreen bold',
                Token.OutPrompt: '#990000',
                Token.OutPromptNum: '#ansibrightred bold',
            }

        style_overrides.update(self.highlighting_style_overrides)
        style = merge_styles([
            style_from_pygments_cls(style_cls),
            style_from_pygments_dict(style_overrides),
        ])

Looks like we can update this from ipython_config.py

from pygments.token import Token
c.TerminalInteractiveShell.highlighting_style_overrides = {
    Token.Prompt: '#cc6666',
}

image

AdrienLemaire avatar Jan 22 '20 01:01 AdrienLemaire

Investigating the lack of color for ipdb shell commands

in prompt_toolkit/styles/style.py, I set __import__('pprint').pprint([vars(s) for s in styles]) in merge_styles to record the difference between ipdb and ipython terminal shells:

Looks like in ipdb's case, a style is added twice. It's being called from Application._create_merged_style in prompt_toolkit/application/application.py, itself only called during initialization of Application.

Thus we're re-initializing Application late in the process and nuking all the style setting done previously.

Application seems to get initialized from PromptSession initialization in prompt_toolkit/shortcuts/prompt.py

Calling ipython in a shell will only call TerminalInteractiveShell, but ipdb will call TerminalInteractiveShell followed by TerminalPdb.

IPython/terminal/interactiveshell.py

class TerminalInteractiveShell(InteractiveShell):
    @property
    def debugger_cls(self):
        return Pdb if self.simple_prompt else TerminalPdb

ipdb/main.py

debugger_cls = shell.debugger_cls

The shell.debugger_cls had been called and set up with ipapp.initialize()

TerminalInteractiveShell inherits Interactiveshell

IPython/core/ultratb.py

class VerboseTB(TBTools):
    def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
                 tb_offset=0, long_header=False, include_vars=True,
                 check_cache=None, debugger_cls = None,
                 parent=None, config=None):
        self.debugger_cls = debugger_cls or debugger.Pdb

    def debugger(self, force=False):
        if force or self.call_pdb:
            if self.pdb is None:
                self.pdb = self.debugger_cls()

IPython/core/crashhandler.py

class CrashHandler(object):
    def __call__(self, etype, evalue, etb):
        TBhandler = ultratb.VerboseTB(
            color_scheme=color_scheme,
            long_header=1,
            call_pdb=self.call_pdb,
        )

IPython/terminal/ipapp.py

class IPAppCrashHandler(CrashHandler):
    ...

class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
    crash_handler_class = IPAppCrashHandler

Realizing that althought IPython uses TerminalInteractiveShell and calls debugger_cls, the TerminalPdb class is never instantiated!!!

Not sure how to debug this further, I do not understand how ipython colorizes text in the ipython shell image

AdrienLemaire avatar Jan 22 '20 04:01 AdrienLemaire

ipdb is a lightweight wrapper around IPython debugger. You might want to ask help to the IPython community.

gotcha avatar Jan 22 '20 08:01 gotcha

I went down this rabbit hole yesterday, and the solution does lie within IPython. IPython uses two different color schemes: one is Pygments, and the other one is changed through c.InteractiveShell.colors in the config file. For the second one there are very limited options and they only use basic 8-bit colors, presumably for compatibility. Using different ANSI escape codes, you can get a lot of much nicer colors depending on what your terminal supports.

If you compare this to master, you can see all the files that need to be changed to add the theme. It's probably possible to do all of that through the config file, but I'm not sure how.

zacharesmer avatar Oct 03 '20 03:10 zacharesmer

Since this is the first hit on the googz for change ipdb colors - In my case the blues were too dark against the black background. Here's how you change the theme:

  1. Run: pip install ipdb
  2. Run: ipython profile create
  3. edit ~/ipython/profile_default/ipython_config.py
  4. Uncomment / change the line c.InteractiveShell.colors = (about line 442) to c.InteractiveShell.colors = 'Linux'
  5. Celebrate!

camAtGitHub avatar Feb 03 '23 08:02 camAtGitHub

@camAtGitHub Thanks a lot for that walkthrough !

gotcha avatar Feb 03 '23 20:02 gotcha

@gotcha Is there currently a way to tell ipdb to start a non-default ipython-profile?

my usecase:
I use startup-files of the default ipython-profile for interactive sessions,
but when debugging the application with pdb, i don't want that startup-code to be run.

as a quickfix, I'm currently wrapping my all code in startup-file in a condition like this:

import os
is_ipython = int(os.getenv("IS_IPYTHON", "0"))

if is_ipython:
    print(f"\nRunning {__file__}")
    .... actual startup-code ....

an ipdb-config setting to start ipdb initialised with an "ipdb-"ipython-profile would nice I think:

[ipdb]
profile=ipdb

woutervh avatar Feb 04 '23 13:02 woutervh

I'll create a PR for this

woutervh avatar Mar 04 '23 22:03 woutervh

See https://github.com/gotcha/ipdb/pull/266

woutervh avatar Mar 13 '23 15:03 woutervh