Skip to content

Changed tempfile.NamedTemporaryFile mode to 'w' - #3739

Open
H-Sorkatti wants to merge 1 commit into
pallets:mainfrom
H-Sorkatti:fix-tempfile-mode
Open

Changed tempfile.NamedTemporaryFile mode to 'w'#3739
H-Sorkatti wants to merge 1 commit into
pallets:mainfrom
H-Sorkatti:fix-tempfile-mode

Conversation

@H-Sorkatti

@H-Sorkatti H-Sorkatti commented Jul 31, 2026

Copy link
Copy Markdown

Inside src/click/_termui_impl.py, the function get_pager_file delegates the creation of a tempfile to _tempfilepager, which returns a BinaryIO object of the opened file:

f = tempfile.NamedTemporaryFile(mode="wb", delete=False)
try:
    yield t.cast(t.BinaryIO, f), encoding, color
...

Which is called by _pager_contextmanager in

...
if pager_cmd_parts:
        if WIN:
            return _tempfilepager(pager_cmd_parts, color)
        return _pipepager(pager_cmd_parts, color)
...
    if WIN or sys.platform.startswith("os2"):
        return _tempfilepager(["more"], color)
    return _pipepager(["less"], color)

In the end get_pager_file

def get_pager_file(color: bool | None = None) -> t.Generator[t.TextIO, None, None]:
    ...
    with _pager_contextmanager(color=color) as (stream, encoding, color):
    # Split streams by capabilities rather than the abstract TextIO /
    # BinaryIO annotations: buffered text streams can be unwrapped to bytes,
    # while other streams are yielded as-is.
    wrapper: MaybeStripAnsi | None = None
        if _has_binary_buffer(stream):
            # Text stream backed by a binary buffer.
            wrapper = MaybeStripAnsi(stream.buffer, color=color, encoding=encoding)
            stream = wrapper
        try:
            # Narrow the BinaryIO | TextIO union that _pager_contextmanager
            # yields; the caller writes text to the pager.
            yield t.cast(t.TextIO, stream)
        ...

In the above yield t.cast(t.TextIO, stream) stream object will be BinaryIO, contradicting the TextIO annotation of the return value, all because it was created with the mode "wb" earlier.

Then if a caller tries: stream.write("some text") it will raise an exception:
TypeError: a bytes-like object is required, not 'str'

FIX:
In _tempfilepager, create the temp file with mode='w'

f = tempfile.NamedTemporaryFile(mode="w", delete=False)

…ager_file stated return value of typing.TextIO
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant