Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

click.testing.CliRunner.invoke prevents use of pdb #843

Open
rsyring opened this issue Aug 27, 2017 · 7 comments
Open

click.testing.CliRunner.invoke prevents use of pdb #843

rsyring opened this issue Aug 27, 2017 · 7 comments
Labels

Comments

@rsyring
Copy link

rsyring commented Aug 27, 2017

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.

@jtcho
Copy link

jtcho commented May 16, 2018

@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.

@segevfiner
Copy link
Contributor

segevfiner commented Oct 7, 2018

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.

@rcoup
Copy link

rcoup commented Jun 27, 2019

This might be useful for some:

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

@delijati
Copy link

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")

@Saif807380
Copy link
Contributor

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

@jmlrt
Copy link

jmlrt commented Jun 22, 2021

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.

@Fabien-GELUS

This comment was marked as off-topic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

9 participants