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

"ValueError: I/O operation on closed file." with click's CliRunner (capturing) #3344

Closed
blueyed opened this issue Mar 26, 2018 · 12 comments
Closed
Labels
plugin: capture related to the capture builtin plugin plugin: debugging related to the debugging builtin plugin type: bug problem that needs to be addressed

Comments

@blueyed
Copy link
Contributor

blueyed commented Mar 26, 2018

With click's CliRunner I've noticed that it throws a ValueError when pytest's
pdb gets used in the CliRunner.isolation context:

test_pytest_capture.py:

def test_click_isolation():
    from click.testing import CliRunner

    runner = CliRunner()
    with runner.isolation() as out:
        print('isolation')
        __import__('pdb').set_trace()
        print('END')
        print(out, out.getvalue())

Test run:

% pytest test_pytest_capture.py
==================================== test session starts ====================================
platform linux -- Python 3.6.4, pytest-3.5.1.dev7+ged118d7f, py-1.5.3, pluggy-0.6.0
rootdir: …/Vcs/click, inifile:
collected 1 item                                                                            

test_pytest_capture.py 
>>>>>>>>>>>>>>>>>>>>>>>>>> PDB set_trace (IO-capturing turned off) >>>>>>>>>>>>>>>>>>>>>>>>>>
> …/Vcs/click/test_pytest_capture.py(8)test_click_isolation()
-> print('END')
(Pdb) c
END
F                                                              [100%]

========================================= FAILURES ==========================================
___________________________________ test_click_isolation ____________________________________

    def test_click_isolation():
        from click.testing import CliRunner
    
        runner = CliRunner()
        with runner.isolation() as out:
            print('isolation')
            __import__('pdb').set_trace()
>           print('END')
E           ValueError: I/O operation on closed file.

test_pytest_capture.py:8: ValueError
================================= 1 failed in 0.77 seconds ==================================

When using -s bdb.BdbQuit is raised:

% pytest test_pytest_capture.py -s
==================================== test session starts ====================================
platform linux -- Python 3.6.4, pytest-3.5.1.dev7+ged118d7f, py-1.5.3, pluggy-0.6.0
rootdir: …/Vcs/click, inifile:
collected 1 item                                                                            

test_pytest_capture.py F

========================================= FAILURES ==========================================
___________________________________ test_click_isolation ____________________________________

    def test_click_isolation():
        from click.testing import CliRunner
    
        runner = CliRunner()
        with runner.isolation() as out:
            print('isolation')
            __import__('pdb').set_trace()
>           print('END')

test_pytest_capture.py:8: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
test_pytest_capture.py:8: in test_click_isolation
    print('END')
/usr/lib/python3.6/bdb.py:48: in trace_dispatch
    return self.dispatch_line(frame)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <pdb.Pdb object at 0x7f35b42e8710>, frame = <frame object at 0x7f35b429f848>

    def dispatch_line(self, frame):
        if self.stop_here(frame) or self.break_here(frame):
            self.user_line(frame)
>           if self.quitting: raise BdbQuit
E           bdb.BdbQuit

/usr/lib/python3.6/bdb.py:67: BdbQuit
================================= 1 failed in 0.06 seconds ==================================

The ValueError comes from out.getvalue really, the location is off due to the
pdb.set_trace (see #3237).

pytest.testing.isolation: https://github.com/pallets/click/blob/55682f6f5348f5220a557f89c3a796321a52aebf/click/testing.py#L139

@pytestbot
Copy link
Contributor

GitMate.io thinks possibly related issues are #14 (ValueError: I/O operation on closed file), #2370 (IOError: close() called during concurrent operation on the same file object.), #1873 (with capsys.disabled() causes "I/O operation on closed file"), #3174 (pytest 3.4 breaks test with CherryPy - no attribute 'testscollected' & I/O operation on closed file), and #1585 (Capture is all wrong).

@blueyed
Copy link
Contributor Author

blueyed commented Mar 26, 2018

I've thought that #2619 might have helped here, but it does not - but without having investigated much it might go in the right direction.

It looks a bit like pytest should maybe restore / handle the changed output stream(s) from the outer context manager, but uses the one(s) from before the test started.

@nicoddemus nicoddemus added plugin: capture related to the capture builtin plugin plugin: debugging related to the debugging builtin plugin labels Mar 27, 2018
@blueyed
Copy link
Contributor Author

blueyed commented Mar 27, 2018

Ref: pallets/click#654

@jwillis0720
Copy link

@blueyed why did you close this?

@itobysq
Copy link

itobysq commented Nov 24, 2021

@blueyed how did you resolve this issue? I am facing the same problem.

@raphaelboudreault
Copy link

@blueyed Was this resolved? Why is this closed?

@elasticdotventures
Copy link

@blueyed Was this resolved? Why is this closed?

This aimclub/FEDOT#765 was solved this by disabling the logging in stdout.
the issue is related to how logging is handled between click & pytest

a potential resolution to pytest cli is to add the "--capture=no" or "-s" (note: -s is a shortcut) parameter which will disable log capturing.

@Solvero
Copy link

Solvero commented Oct 19, 2022

I followed suggestion to remove CliRunner. Seems that it works this way (link to docs):

with function_under_test.make_context('function_under_test', ['arg1', 'arg2']) as ctx:
  result = function_under_test.invoke(ctx)

@snirbenyosef
Copy link

@Solvero result is allways None for you to ?

does someone found a way to fix the issue? or to overcome it?

@Solvero
Copy link

Solvero commented Apr 18, 2023

@snirbenyosef I've just checked. I have correct value returned (in my case its integer).

Please double check that you return value in 'function_under_test'.

@snirbenyosef
Copy link

@Solvero I meant I want the stdout and the exit_code, is it possible?

@Solvero
Copy link

Solvero commented Apr 18, 2023

For that I would use subprocess instead:

resp = subprocess.check_output(...)
assert resp.returncode == 0
assert resp.stdout ....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
plugin: capture related to the capture builtin plugin plugin: debugging related to the debugging builtin plugin type: bug problem that needs to be addressed
Projects
None yet
Development

No branches or pull requests

9 participants