click icon indicating copy to clipboard operation
click copied to clipboard

click.testing.CliRunner.invoke prevents use of pdb

Open rsyring opened this issue 7 years ago • 7 comments

Will someone please re-open #138. It's still a problem with Click 6.7. In particular, my stack trace ends with:

  File "/home/rsyring/projects/agari-adm-src/agariadm/cli.py", line 64, in batch
    import pdb; pdb.set_trace()
  File "/usr/lib/python3.5/bdb.py", line 52, in trace_dispatch
    return self.dispatch_return(frame, arg)
  File "/usr/lib/python3.5/bdb.py", line 96, in dispatch_return
    if self.quitting: raise BdbQuit
bdb.BdbQuit

And there is explanation about why this is happening in the related issue.

rsyring avatar Aug 27 '17 23:08 rsyring

@rsyring Perhaps you've figured this out in the interim, but the workaround that I've come up for this is to mock out click.testing.make_input_stream and replace the returned value with the original sys.stdin.

For example:

import sys

from mock import patch

patcher = patch('click.testing.make_input_stream')
m_make_input_stream = patcher.start()
m_make_input_stream.return_value = sys.stdin

# ...

patcher.stop()

Please let me know if you have any more questions.

jtcho avatar May 16 '18 08:05 jtcho

Since CliRunner overrides sys.{stdin,stdout} and pdb depends on them, it's quite expected that this doesn't just work. pytest, which also does IO redirection, monkey patches the global pdb.set_trace so that it disables IO redirection when called allowing it work even if IO redirection is enabled. But I think click generally tries to avoid affecting global state...

You can try this workaround:

import sys
import pdb
import click
from click.testing import CliRunner


stdin, stdout = sys.stdin, sys.stdout


def set_trace():
    pdb.Pdb(stdin=stdin, stdout=stdout).set_trace()


@click.command()
def main():
    set_trace()


if __name__ == '__main__':
    runner = CliRunner()
    print(runner.invoke(main))

How click should be handling this issue is left open for discussion.

segevfiner avatar Oct 07 '18 20:10 segevfiner

This might be useful for some:

Click CliRunner with PDB working better under pytest https://gist.github.com/rcoup/2566c92a1c47d66cfb429a6e3cb0cca2

rcoup avatar Jun 27 '19 15:06 rcoup

I use this snipped and it works basically always (argsparse, click, sys.argv):

import unittest
import pytest

from thing.__main__ import cli


class TestCli(unittest.TestCase):

    @pytest.fixture(autouse=True)
    def capsys(self, capsys):
        self.capsys = capsys

    def test_cli(self):
        with pytest.raises(SystemExit) as ex:
            cli(["create", "--name", "test"])
        self.assertEqual(ex.value.code, 0)
        out, err = self.capsys.readouterr()
        self.assertEqual(out, "Succesfully created test\n")

delijati avatar May 26 '20 22:05 delijati

I tried out a few samples and workarounds from here. The CliRunner replaces the stdin and stdout with _NamedTextIOWrapper on top of EchoingStdin and io.BytesIO objects respectively. The return value of make_input_stream and io.BytesIO is simply not compatible with pdb which uses sys.stdin and sys.stdout.

I went through pdb source code as well and from what I can tell, BdbQuit is raised when the debugger is quit and the program is aborted though there could be some other places as well that raise it. I don't think it has anything to do with the exception, just that which stream is being used to output it.

In my opinion, it will be better to leave this as it is until there is a better way to mock sys.stdin and sys.stdout inside CliRunner. One way could be to somehow detect the usage of pdb inside CliRunner and accordingly mock the streams. Perhaps an extra flag could serve this purpose. Or mock pdb itself like pytest does as mentioned by @segevfiner

Saif807380 avatar May 11 '21 17:05 Saif807380

I had the same error, calling PDB from pytest using pytest --pdb, with import pytest; pytest.set_trace() in my code instead of import pdb; pdb.set_trace() fixed it for me.

jmlrt avatar Jun 22 '21 09:06 jmlrt

Still got the same issue BdbQuit with Click 7.1.2, none of the workarounds work for me

Fabien-GELUS avatar May 31 '22 14:05 Fabien-GELUS