prompt-toolkit / prompt-toolkit/python-prompt-toolkit

Incompatibility with pytest capsys

Open
#1,852 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
10.6k
Forks
815
PR merge metrics
No merged PRs in 30d

Description

Hi,

Here is something i have noticed while testing the project i manage.

Sounds like print_formatted_text and capsys does not interoperate together.

Do you have any idea how to deal with that problem?
Does it make sense to patch one or the other project?

Test

from prompt_toolkit import print_formatted_text

def test_1(capsys):
    print_formatted_text("1")


def test_2(capsys):
    print_formatted_text("2")

Result

test_pt.py::test_1 PASSED                                                                                                                              [ 50%]
test_pt.py::test_2 FAILED                                                                                                                              [100%]

========================================================================== FAILURES ==========================================================================
___________________________________________________________________________ test_2 ___________________________________________________________________________

capsys = <_pytest.capture.CaptureFixture object at 0x7fbc1f55df10>

    def test_2(capsys):
>       print_formatted_text("2")

test_pt.py:12: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../Software/miniconda3/envs/blissdev/lib/python3.9/site-packages/prompt_toolkit/shortcuts/utils.py:163: in print_formatted_text
    render()
../../Software/miniconda3/envs/blissdev/lib/python3.9/site-packages/prompt_toolkit/shortcuts/utils.py:138: in render
    renderer_print_formatted_text(
../../Software/miniconda3/envs/blissdev/lib/python3.9/site-packages/prompt_toolkit/renderer.py:813: in print_formatted_text
    output.flush()
../../Software/miniconda3/envs/blissdev/lib/python3.9/site-packages/prompt_toolkit/output/plain_text.py:57: in flush
    flush_stdout(self.stdout, data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

stdout = <_io.TextIOWrapper encoding='UTF-8'>, data = '2\r\n'

    def flush_stdout(stdout: TextIO, data: str) -> None:
        # If the IO object has an `encoding` and `buffer` attribute, it means that
        # we can access the underlying BinaryIO object and write into it in binary
        # mode. This is preferred if possible.
        # NOTE: When used in a Jupyter notebook, don't write binary.
        #       `ipykernel.iostream.OutStream` has an `encoding` attribute, but not
        #       a `buffer` attribute, so we can't write binary in it.
        has_binary_io = hasattr(stdout, "encoding") and hasattr(stdout, "buffer")
    
        try:
            # Ensure that `stdout` is made blocking when writing into it.
            # Otherwise, when uvloop is activated (which makes stdout
            # non-blocking), and we write big amounts of text, then we get a
            # `BlockingIOError` here.
            with _blocking_io(stdout):
                # (We try to encode ourself, because that way we can replace
                # characters that don't exist in the character set, avoiding
                # UnicodeEncodeError crashes. E.g. u'\xb7' does not appear in 'ascii'.)
                # My Arch Linux installation of july 2015 reported 'ANSI_X3.4-1968'
                # for sys.stdout.encoding in xterm.
                out: IO[bytes]
                if has_binary_io:
>                   stdout.buffer.write(data.encode(stdout.encoding or "utf-8", "replace"))
E                   ValueError: I/O operation on closed file.

../../Software/miniconda3/envs/blissdev/lib/python3.9/site-packages/prompt_toolkit/output/flush_stdout.py:32: ValueError
================================================================== short test summary info ===================================================================
FAILED test_pt.py::test_2 - ValueError: I/O operation on closed file.

My env

pytest                        7.2.0
pytest-cov                    4.0.0
pytest-mock                   3.10.0
pytest-profiling              1.7.0
pytest-redis                  3.0.2
pytest-rerunfailures          10.3
pytest-xvfb                   2.0.0
prompt-toolkit                3.0.33

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the two-test reproducer with pytest and capsys, then trace the failure through shortcuts/utils.py, renderer.py, output/plain_text.py, and output/flush_stdout.py. Done means both tests pass without the I/O operation on closed file error while preserving the reported print_formatted_text behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
cli, testing-qa
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.