Skip to content

ResourceWarning emitted when io.TextIOWrapper object yielded from nested contextmanager #144276

@danielhollas

Description

@danielhollas

Bug report

Bug description:

The following code triggers a ResourceWarning

import io
import tempfile
import contextlib

@contextlib.contextmanager
def my_wrapped_open():
    with tempfile.NamedTemporaryFile('bw') as handle:
        handle.write(b'content')
        handle.seek(0)
        yield io.TextIOWrapper(handle, encoding='utf-8')

with my_wrapped_open():
    pass
uvx [email protected] -Wd reproduce.py
cpython-3.15.0a5-linux-x86_64-gnu/lib/python3.15/tempfile.py:520: ResourceWarning: unclosed file <_io.TextIOWrapper name='/tmp/tmphv2hjg_t' encoding='utf-8'>
  return func(*args, **kwargs)
ResourceWarning: Enable tracemalloc to get the object allocation traceback

The ResourceWarning disappears if the TextIO object is first assigned to a variable before yielding

@contextlib.contextmanager
def my_wrapped_open():
    with tempfile.NamedTemporaryFile('bw') as handle:
        handle.write(b'content')
        handle.seek(0)
        textio = io.TextIOWrapper(handle, encoding='utf-8')
        yield textio

It also disappears if the outer context is assigned to a variable like this

with my_wrapped_open() as _:
    pass

I am not sure if this is a bug in CPython, but it is for sure a surprising behaviour that we do not fully understand.

This is a full stack trace when enabling tracemalloc

export PYTHONTRACEMALLOC=20uvx [email protected] -Wd reproduce.py 
cpython-3.15.0a5-linux-x86_64-gnu/lib/python3.15/tempfile.py:520: ResourceWarning: unclosed file <_io.TextIOWrapper name='/tmp/tmpq48qq4rk' encoding='utf-8'>
  return func(*args, **kwargs)
Object allocated at (most recent call last):
  File "/home/hollas/atmospec/aiida-core/reproduce.py", lineno 13
    with my_wrapped_open():
  File "/home/hollas/.local/share/uv/python/cpython-3.15.0a5-linux-x86_64-gnu/lib/python3.15/contextlib.py", lineno 141
    return next(self.gen)
  File "/home/hollas/atmospec/aiida-core/reproduce.py", lineno 11
    yield io.TextIOWrapper(handle, encoding='utf-8')

CPython versions tested on:

3.15, 3.9, 3.10, 3.11, 3.12, 3.13, 3.14

Operating systems tested on:

Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions