Skip to content

--pdb causes stderr/stdout output to be hidden #1223

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

Closed
foxx opened this issue Dec 4, 2015 · 11 comments
Closed

--pdb causes stderr/stdout output to be hidden #1223

foxx opened this issue Dec 4, 2015 · 11 comments
Labels
topic: reporting related to terminal output and user-facing messages and errors type: bug problem that needs to be addressed

Comments

@foxx
Copy link
Contributor

foxx commented Dec 4, 2015

For some reason, if I specify --pdb, the stdout/stderr capture output doesn't get printed, neither before or after the pdb shell.

Here are the steps to reproduce.

Test file

$ cat hello.py
def test_wtf():
    print("WTFWTFTWF")
    raise Exception()

Without PDB

$ py.test hello.py
============================= test session starts ==============================
platform linux -- Python 3.4.3, pytest-2.8.2, py-1.4.30, pluggy-0.3.1
rootdir: /vagrant, inifile:
plugins: cov-2.2.0, capturelog-0.7
collected 1 items

hello.py F

=================================== FAILURES ===================================
___________________________________ test_wtf ___________________________________

    def test_wtf():
        print("WTFWTFTWF")
>       raise Exception()
E       Exception

hello.py:3: Exception
----------------------------- Captured stdout call -----------------------------
WTFWTFTWF
================= 1 failed, 1 pytest-warnings in 0.02 seconds ==================

With PDB

$ py.test hello.py  --pdb
============================= test session starts ==============================
platform linux -- Python 3.4.3, pytest-2.8.2, py-1.4.30, pluggy-0.3.1
rootdir: /vagrant, inifile:
plugins: cov-2.2.0, capturelog-0.7
collected 1 items

hello.py F
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> traceback >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    def test_wtf():
        print("WTFWTFTWF")
>       raise Exception()
E       Exception

hello.py:3: Exception
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> entering PDB >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
> /vagrant/hello.py(3)test_wtf()
-> raise Exception()
(Pdb)


================= 1 failed, 1 pytest-warnings in 4.39 seconds ==================
@RonnyPfannschmidt RonnyPfannschmidt added type: bug problem that needs to be addressed topic: reporting related to terminal output and user-facing messages and errors labels Dec 4, 2015
@nicoddemus
Copy link
Member

I think here's the line with the problem... suspendcapture returns the out and err contents which should be printed at that point, but is thrown away.

@foxx
Copy link
Contributor Author

foxx commented Dec 5, 2015

Thanks for the quick reply, looks like you're right, it should instead be doing something like;

out, err = capman.suspendcapture()
    if outcome.excinfo is not None:
        sys.stdout.write(out)
        sys.stderr.write(err)

@nicoddemus I think that stdout/stderr should probably be printed /before/ pdb gets called, would you agree?

@RonnyPfannschmidt
Copy link
Member

For correct output you need to obtain the terminal writer plugin, like settrace does for example

@foxx
Copy link
Contributor Author

foxx commented Dec 5, 2015

@RonnyPfannschmidt Sorry I'm not quite following, are you saying this is a code bug or user error?

@nicoddemus
Copy link
Member

@foxx I think Ronny meant about the code you posted, that you should use the terminal writer plugin instead of writing directly to sys.stdout or sys.stderr.

@RonnyPfannschmidt
Copy link
Member

Exactly, thanks for the clarification

@nicoddemus
Copy link
Member

@foxx any chance of opening a PR with this fix? 😁

@foxx
Copy link
Contributor Author

foxx commented Jan 7, 2016

Just tried getting this to work locally, but can't seem to figure it out.

def pytest_configure(config):
    ....
    PdbInvoke._config = config
    ....

def pytest_exception_interact(self, node, call, report):
    import _pytest.config
    capman = node.config.pluginmanager.getplugin("capturemanager")
    if capman:
        capman.suspendcapture(in_=True)
    tw = _pytest.config.create_terminal_writer(self._config)
    tw.line()
    tw.sep(">", "PDB exception interact (IO-capturing turned off)")
    _enter_pdb(node, call.excinfo, report)

This is an almost exact copy of what is being done with set_trace, as seen here;

            capman = self._pluginmanager.getplugin("capturemanager")
            if capman:
                capman.suspendcapture(in_=True)
            tw = _pytest.config.create_terminal_writer(self._config)
            tw.line()
            tw.sep(">", "PDB set_trace (IO-capturing turned off)")
            self._pluginmanager.hook.pytest_enter_pdb()

There's a lot of monkeypatching and magic in here that I don't really understand, I could probably figure it out but it would take me 7396749373 times longer than others with an understanding of the internals.

If someone can give me a pointer in the right direction then I'll happily try again

@foxx
Copy link
Contributor Author

foxx commented Jan 7, 2016

I've also tried calling write() directly with out/err, with no effect;

        if capman:
            out, err = capman.suspendcapture(in_=True)
        tw = _pytest.config.create_terminal_writer(self._config)
        tw.line()
        tw.sep(">", "PDB exception interact (IO-capturing turned off)")
        tw.write(out)
        tw.write(err)

Although tw.write("wtf") seems to work fine.

@nicoddemus
Copy link
Member

I would suggest to dig directly into the pytest's source instead of trying to muck around with the plugins. I think it would be just a matter of changing the code around this line to something like this (untested):

    def pytest_exception_interact(self, node, call, report):
        capman = node.config.pluginmanager.getplugin("capturemanager")
        if capman:
            out, err = capman.suspendcapture(in_=True)
            sys.stdout.write(out)
            sys.stdout.write(err)
        _enter_pdb(node, call.excinfo, report)

I would leave out trying to use "terminalwriter" until this was working (and even then I'm not it would give out much).

@foxx
Copy link
Contributor Author

foxx commented Jan 8, 2016

Yeah that works much better, I would have done this before but was stuck trying to make terminalwriter work. PR coming shortly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: reporting related to terminal output and user-facing messages and errors type: bug problem that needs to be addressed
Projects
None yet
Development

No branches or pull requests

3 participants