Repository: ipython/ipython

Issue:
Is tab supposed to work in the ultratb prompt ?
I really love ultratb and I probably overuse it (instead of logging and running I often raise)

When I press tab I get a tab char inserted into the ipdb REPL.

Is tab supposed to work in ultratb or does tab completion require `prompt_toolkit`? Maybe it is not working on my machine or maybe it is working as it is supposed to--not sure. 

If it is not supposed to work would it make sense to supply TerminalPdb instead of debugger.Pdb ? Maybe that could be exposed as a kwargs option...

```
Python 3.9.10 (main, Jan 17 2022, 00:00:00) 
import IPython
@>>> IPython.version_info
(8, 0, 1, '')

kitty 0.21.2 created by Kovid Goyal
fish, version 3.3.1
```


Discussion:
So I'm not quite sure what you are asking, not how you are using it, but for me:

```
In [1]: import ipdb
   ...:
   ...: ipdb.set_trace()
--Call--
> /Users/bussonniermatthias/dev/ipython/IPython/core/displayhook.py(252)__call__()
    251
--> 252     def __call__(self, result=None):
    253         """Printing with history cache management.

ipdb> imp<tab> # complete to import
```

It does need prompt toolkit though I believe. 

<img width="273" alt="Screen Shot 2022-01-28 at 20 57 17" src="https://user-images.githubusercontent.com/335567/151613083-f6736dd0-c801-44e1-8b9c-997e546ca37a.png">
 
ah I use it like this

```
from IPython.core import ultratb

sys.excepthook = ultratb.FormattedTB(
    mode="Verbose" if args.verbose > 0 else "Context", color_scheme="Neutral", call_pdb=1
)
```

I have prompt_toolkit installed but my point was that https://github.com/ipython/ipython/blob/master/IPython/core/ultratb.py does not seem to import that library
this does not seem to work either

```
from IPython.terminal.debugger import TerminalPdb

sys.excepthook = ultratb.FormattedTB(
                    mode="Verbose" if args.verbose > 0 else "Context",
                    color_scheme="Neutral",
                    call_pdb=1,
                    debugger_cls=TerminalPdb,
                )
```
I also get an IndentationError immediately after pressing enter

```
@ipdb> for key, value in extra_dict.items():    
*** IndentationError: expected an indented block
```

so maybe part of it is a configuration error or maybe a limitation of pdb
It's a bug. You can patch locally:


```
class TBTools(colorable.Colorable):
    """Basic tools used by all traceback printer classes."""

    # Number of frames to skip when reporting tracebacks
    tb_offset = 0

    def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
        # Whether to call the interactive pdb debugger after printing
        ...
-        if call_pdb:
-            self.pdb = debugger.Pdb()
-        else:
-            self.pdb = None
+        self.pdb = None

```

And then using 


```
sys.excepthook = ultratb.AutoFormattedTB(
    mode="Verbose",
    color_scheme="Neutral",
    call_pdb=1,
    debugger_cls=TerminalPdb,
)
```

Works for me. 

I need to look into a proper fix, and see if it has other effects, or you can try to send a PR. 



Resolving patch:
diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py
--- a/IPython/core/ultratb.py
+++ b/IPython/core/ultratb.py
@@ -207,7 +207,16 @@ class TBTools(colorable.Colorable):
     # Number of frames to skip when reporting tracebacks
     tb_offset = 0
 
-    def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
+    def __init__(
+        self,
+        color_scheme="NoColor",
+        call_pdb=False,
+        ostream=None,
+        parent=None,
+        config=None,
+        *,
+        debugger_cls=None,
+    ):
         # Whether to call the interactive pdb debugger after printing
         # tracebacks or not
         super(TBTools, self).__init__(parent=parent, config=config)
@@ -227,9 +236,10 @@ def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=
 
         self.set_colors(color_scheme)
         self.old_scheme = color_scheme  # save initial value for toggles
+        self.debugger_cls = debugger_cls or debugger.Pdb
 
         if call_pdb:
-            self.pdb = debugger.Pdb()
+            self.pdb = debugger_cls()
         else:
             self.pdb = None
 
@@ -350,9 +360,6 @@ class ListTB(TBTools):
     Because they are meant to be called without a full traceback (only a
     list), instances of this class can't call the interactive pdb debugger."""
 
-    def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
-        TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
-                         ostream=ostream, parent=parent,config=config)
 
     def __call__(self, etype, value, elist):
         self.ostream.flush()
@@ -628,8 +635,15 @@ def __init__(
         tb_offset=1 allows use of this handler in interpreters which will have
         their own code at the top of the traceback (VerboseTB will first
         remove that frame before printing the traceback info)."""
-        TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
-                         ostream=ostream, parent=parent, config=config)
+        TBTools.__init__(
+            self,
+            color_scheme=color_scheme,
+            call_pdb=call_pdb,
+            ostream=ostream,
+            parent=parent,
+            config=config,
+            debugger_cls=debugger_cls,
+        )
         self.tb_offset = tb_offset
         self.long_header = long_header
         self.include_vars = include_vars
@@ -642,7 +656,6 @@ def __init__(
             check_cache = linecache.checkcache
         self.check_cache = check_cache
 
-        self.debugger_cls = debugger_cls or debugger.Pdb
         self.skip_hidden = True
 
     def format_record(self, frame_info):


Test patch: