Skip to content

TerminalInteractiveShell determines is_tty / _use_simple_prompt on import time #11745

@blueyed

Description

@blueyed

When using e.g. --pdbcls=IPython.terminal.debugger:TerminalPdb with pytest, it might import TerminalPdb with output capturing being active, which results in _use_simple_prompt being True then.

The debugger_cls will return Pdb then (which makes --pdbcls=ipdb:__main__.debugger_cls not crash, but use the simple prompt).

The crash:

    def test_foo():
        print(1)
>       __import__('pytest').set_trace()

t-pdb.py:7:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
src/_pytest/debugging.py:221: in set_trace
    _pdb = cls._init_pdb(*args, **kwargs)
src/_pytest/debugging.py:211: in _init_pdb
    _pdb = _PdbWrapper(**kwargs)
../ipython/IPython/terminal/debugger.py:27: in __init__
    self.pt_init()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <_pytest.debugging.pytestPDB._init_pdb.<locals>._PdbWrapper object at 0x7f74ea3c75f8>

        self.pt_app = PromptSession(
                            message=(lambda: PygmentsTokens(get_prompt_tokens())),
                            editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
                            key_bindings=kb,
                            history=self.shell.debugger_history,
                            completer=self._ptcomp,
                            enable_history_search=True,
                            mouse_support=self.shell.mouse_support,
                            complete_style=self.shell.pt_complete_style,
>                           style=self.shell.style,
                            inputhook=self.shell.inputhook,
                            color_depth=self.shell.color_depth,
        )
E       AttributeError: 'TerminalInteractiveShell' object has no attribute 'style'

../ipython/IPython/terminal/debugger.py:62: AttributeError

Code reference:

# conservatively check for tty
# overridden streams can result in things like:
# - sys.stdin = None
# - no isatty method
for _name in ('stdin', 'stdout', 'stderr'):
_stream = getattr(sys, _name)
if not _stream or not hasattr(_stream, 'isatty') or not _stream.isatty():
_is_tty = False
break
else:
_is_tty = True
_use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
class TerminalInteractiveShell(InteractiveShell):
space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
'to reserve for the completion menu'
).tag(config=True)
pt_app = None
debugger_history = None
simple_prompt = Bool(_use_simple_prompt,

  1. I think there should be a way to force usage of the enhanced prompt always (via a new class maybe?)
  2. the is-a-tty check should be done on initialization, not import time
  3. the is-a-tty check should not require all streams to be a tty really (usually it is ok for one of them to be a tty)
  4. it should not crash like this in the first place (i.e. not try to access an attribute that is skipped (
    if self.simple_prompt:
    )

I can think of fixes in pytest itself (e.g. disabling capturing for when the debugger class is imported, or importing it only later), but there are several issues here that should be addressed also.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions