Tinche/aiofiles

Python 3.12 test failures: FAILED tests/test_tempfile.py::test_named_temporary_file[r+] - AttributeError: '_io.TextIOWrapper' object has no attribute 'delete'

mgorny opened this issue · 11 comments

mgorny commented

When running the test suite on Python 3.12.0b1, I'm getting the following test failures:

$ python -m pytest
========================================================= test session starts =========================================================
platform linux -- Python 3.12.0b1+, pytest-7.3.1, pluggy-1.0.0
rootdir: /tmp/aiofiles
plugins: asyncio-0.21.0
asyncio: mode=Mode.STRICT
collected 201 items                                                                                                                   

tests/test_os.py .................................                                                                              [ 16%]
tests/test_simple.py ..                                                                                                         [ 17%]
tests/test_stdio.py ..                                                                                                          [ 18%]
tests/test_tempfile.py ....FFFF.........                                                                                        [ 26%]
tests/threadpool/test_binary.py ............................................................................................... [ 74%]
....                                                                                                                            [ 76%]
tests/threadpool/test_concurrency.py .                                                                                          [ 76%]
tests/threadpool/test_open.py ...                                                                                               [ 78%]
tests/threadpool/test_text.py ............................................                                                      [100%]

============================================================== FAILURES ===============================================================
____________________________________________________ test_named_temporary_file[r+] ____________________________________________________

mode = 'r+'

    @pytest.mark.asyncio
    @pytest.mark.parametrize("mode", ["r+", "w+", "rb+", "wb+"])
    async def test_named_temporary_file(mode):
        """Test named temporary file."""
        data = b"Hello World!" if "b" in mode else "Hello World!"
        filename = None
    
>       async with tempfile.NamedTemporaryFile(mode=mode) as f:

tests/test_tempfile.py:33: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.tox/py312/lib/python3.12/site-packages/aiofiles/base.py:98: in __aenter__
    self._obj = await self._coro
.tox/py312/lib/python3.12/site-packages/aiofiles/tempfile/__init__.py:177: in _temporary_file
    result.delete = f.delete
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <tempfile._TemporaryFileWrapper object at 0x7f68ac328e30>, name = 'delete'

    def __getattr__(self, name):
        # Attribute lookups are delegated to the underlying file
        # and cached for non-numeric results
        # (i.e. methods are cached, closed and friends are not)
        file = self.__dict__['file']
>       a = getattr(file, name)
E       AttributeError: '_io.TextIOWrapper' object has no attribute 'delete'

/usr/lib/python3.12/tempfile.py:478: AttributeError
____________________________________________________ test_named_temporary_file[w+] ____________________________________________________

mode = 'w+'

    @pytest.mark.asyncio
    @pytest.mark.parametrize("mode", ["r+", "w+", "rb+", "wb+"])
    async def test_named_temporary_file(mode):
        """Test named temporary file."""
        data = b"Hello World!" if "b" in mode else "Hello World!"
        filename = None
    
>       async with tempfile.NamedTemporaryFile(mode=mode) as f:

tests/test_tempfile.py:33: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.tox/py312/lib/python3.12/site-packages/aiofiles/base.py:98: in __aenter__
    self._obj = await self._coro
.tox/py312/lib/python3.12/site-packages/aiofiles/tempfile/__init__.py:177: in _temporary_file
    result.delete = f.delete
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <tempfile._TemporaryFileWrapper object at 0x7f68ac32a7b0>, name = 'delete'

    def __getattr__(self, name):
        # Attribute lookups are delegated to the underlying file
        # and cached for non-numeric results
        # (i.e. methods are cached, closed and friends are not)
        file = self.__dict__['file']
>       a = getattr(file, name)
E       AttributeError: '_io.TextIOWrapper' object has no attribute 'delete'

/usr/lib/python3.12/tempfile.py:478: AttributeError
___________________________________________________ test_named_temporary_file[rb+] ____________________________________________________

mode = 'rb+'

    @pytest.mark.asyncio
    @pytest.mark.parametrize("mode", ["r+", "w+", "rb+", "wb+"])
    async def test_named_temporary_file(mode):
        """Test named temporary file."""
        data = b"Hello World!" if "b" in mode else "Hello World!"
        filename = None
    
>       async with tempfile.NamedTemporaryFile(mode=mode) as f:

tests/test_tempfile.py:33: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.tox/py312/lib/python3.12/site-packages/aiofiles/base.py:98: in __aenter__
    self._obj = await self._coro
.tox/py312/lib/python3.12/site-packages/aiofiles/tempfile/__init__.py:177: in _temporary_file
    result.delete = f.delete
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <tempfile._TemporaryFileWrapper object at 0x7f68ac32b110>, name = 'delete'

    def __getattr__(self, name):
        # Attribute lookups are delegated to the underlying file
        # and cached for non-numeric results
        # (i.e. methods are cached, closed and friends are not)
        file = self.__dict__['file']
>       a = getattr(file, name)
E       AttributeError: '_io.BufferedRandom' object has no attribute 'delete'

/usr/lib/python3.12/tempfile.py:478: AttributeError
___________________________________________________ test_named_temporary_file[wb+] ____________________________________________________

mode = 'wb+'

    @pytest.mark.asyncio
    @pytest.mark.parametrize("mode", ["r+", "w+", "rb+", "wb+"])
    async def test_named_temporary_file(mode):
        """Test named temporary file."""
        data = b"Hello World!" if "b" in mode else "Hello World!"
        filename = None
    
>       async with tempfile.NamedTemporaryFile(mode=mode) as f:

tests/test_tempfile.py:33: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.tox/py312/lib/python3.12/site-packages/aiofiles/base.py:98: in __aenter__
    self._obj = await self._coro
.tox/py312/lib/python3.12/site-packages/aiofiles/tempfile/__init__.py:177: in _temporary_file
    result.delete = f.delete
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <tempfile._TemporaryFileWrapper object at 0x7f68ac32b6e0>, name = 'delete'

    def __getattr__(self, name):
        # Attribute lookups are delegated to the underlying file
        # and cached for non-numeric results
        # (i.e. methods are cached, closed and friends are not)
        file = self.__dict__['file']
>       a = getattr(file, name)
E       AttributeError: '_io.BufferedRandom' object has no attribute 'delete'

/usr/lib/python3.12/tempfile.py:478: AttributeError
======================================================= short test summary info =======================================================
FAILED tests/test_tempfile.py::test_named_temporary_file[r+] - AttributeError: '_io.TextIOWrapper' object has no attribute 'delete'
FAILED tests/test_tempfile.py::test_named_temporary_file[w+] - AttributeError: '_io.TextIOWrapper' object has no attribute 'delete'
FAILED tests/test_tempfile.py::test_named_temporary_file[rb+] - AttributeError: '_io.BufferedRandom' object has no attribute 'delete'
FAILED tests/test_tempfile.py::test_named_temporary_file[wb+] - AttributeError: '_io.BufferedRandom' object has no attribute 'delete'
==================================================== 4 failed, 197 passed in 1.77s ====================================================
Tinche commented

Interesting, thanks for doing this. Guess they changed the interface of these classes. Any idea of a remedy?

mgorny commented

I'm afraid I don't have any. I'm just mass-testing Gentoo packages against Python 3.12 right now.

There is a new delete_on_close parameter for tempfile.NamedTemporaryFile in Python 3.12 that may be relevant, but I’m not prepared to wade through all the indirection to propose a patch at the moment.

Tinche commented

I think I got this fixed on main! Let me know if I'm wrong.

I think I got this fixed on main! Let me know if I'm wrong.

Seems to work in Fedora Linux. Thanks!

mgorny commented

I can also confirm that this fixes the problem for me. Could you make a new release, please? This change is a little big for us to backport to Gentoo.

Tinche commented

I was hoping to wait until 3.12 was released in case they break us again, but I can release sooner.

mgorny commented

Technically, 3.12 is in beta (and almost RC) already, so it shouldn't be breaking anything anymore.

Tinche commented

@mgorny alright, I'm ready to release 23.2.0. Can you test once again with main before I do that?

mgorny commented

@mgorny alright, I'm ready to release 23.2.0. Can you test once again with main before I do that?

Sure. It's all green. Thanks!

207 passed, 4 skipped in 2.61s