Skip to content

MockSocket related test_makefile failures with Python 3.13Β #733

Open
@kulikjak

Description

@kulikjak

❓ I'm submitting a ...

  • 🐞 bug report
  • 🐣 feature request
  • ❓ question about the decisions made in the repository

🐞 Describe the bug. What is the current behavior?

When running the Cheroot test suite under Python 3.13, test_bytes_read and test_bytes_written fail with the following error (full trace below):

E                   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <function IOBase.__del__ at 0x7fc35010e8e0>
E                   
E                   Traceback (most recent call last):
E                     File "/usr/lib/python3.13/_pyio.py", line 418, in __del__
E                       self.close()
E                       ~~~~~~~~~~^^
E                     File "/usr/lib/python3.13/_pyio.py", line 818, in close
E                       self.raw.close()
E                       ~~~~~~~~~~~~~~^^
E                     File "/usr/lib/python3.13/socket.py", line 789, in close
E                       self._sock._decref_socketios()
E                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E                   AttributeError: 'MockSocket' object has no attribute '_decref_socketios'

My guess is that this is related the following io changes:
https://docs.python.org/3/whatsnew/3.13.html#io

πŸ’‘ To Reproduce

Run the test suite with Python 3.13.0.

πŸ“‹ Details
Full traceback:

=================================== FAILURES ===================================
_______________________________ test_bytes_read ________________________________

cls = <class '_pytest.runner.CallInfo'>
func = <function call_and_report.<locals>.<lambda> at 0x7fc34e78e8e0>
when = 'call'
reraise = (<class '_pytest.outcomes.Exit'>, <class 'KeyboardInterrupt'>)

    @classmethod
    def from_call(
        cls,
        func: Callable[[], TResult],
        when: Literal["collect", "setup", "call", "teardown"],
        reraise: type[BaseException] | tuple[type[BaseException], ...] | None = None,
    ) -> CallInfo[TResult]:
        """Call func, wrapping the result in a CallInfo.
    
        :param func:
            The function to call. Called without arguments.
        :type func: Callable[[], _pytest.runner.TResult]
        :param when:
            The phase in which the function is called.
        :param reraise:
            Exception or exceptions that shall propagate if raised by the
            function, instead of being wrapped in the CallInfo.
        """
        excinfo = None
        start = timing.time()
        precise_start = timing.perf_counter()
        try:
>           result: TResult | None = func()

cls        = <class '_pytest.runner.CallInfo'>
duration   = 0.005907708022277802
excinfo    = <ExceptionInfo PytestUnraisableExceptionWarning('Exception ignored in: <function IOBase.__del__ at 0x7fc35010e8e0>\n\nTraceback (most...s()\n    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAttributeError: \'MockSocket\' object has no attribute \'_decref_socketios\'\n') tblen=12>
func       = <function call_and_report.<locals>.<lambda> at 0x7fc34e78e8e0>
precise_start = 515484.144903254
precise_stop = 515484.150810962
reraise    = (<class '_pytest.outcomes.Exit'>, <class 'KeyboardInterrupt'>)
result     = None
start      = 1730812298.088149
stop       = 1730812298.0940628
when       = 'call'

/usr/lib/python3.13/vendor-packages/_pytest/runner.py:341: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/usr/lib/python3.13/vendor-packages/_pytest/runner.py:242: in <lambda>
    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
        item       = <Function test_bytes_read>
        kwds       = {}
        runtest_hook = <HookCaller 'pytest_runtest_call'>
/usr/lib/python3.13/vendor-packages/pluggy/_hooks.py:513: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
        firstresult = False
        kwargs     = {'item': <Function test_bytes_read>}
        self       = <HookCaller 'pytest_runtest_call'>
/usr/lib/python3.13/vendor-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
        firstresult = False
        hook_name  = 'pytest_runtest_call'
        kwargs     = {'item': <Function test_bytes_read>}
        methods    = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from '/usr/lib/python3.13/vendor-packages/_pytest/runner.py'>>,
 <HookImpl plugin_name='skipping', plugin=<module '_pytest.skipping' from '/usr/lib/python3.13/vendor-packages/_pytest/skipping.py'>>,
 <HookImpl plugin_name='hypothesispytest', plugin=<module '_hypothesis_pytestplugin' from '/usr/lib/python3.13/vendor-packages/_hypothesis_pytestplugin.py'>>,
 <HookImpl plugin_name='capturemanager', plugin=<CaptureManager _method='fd' _global_capturing=<MultiCapture out=<FDCapture 1 oldfd=5 _state='suspended' tmpfile=<EncodedFile name="<_io.FileIO name=6 mode='rb+' closefd=True>" mode='r+' encoding='utf-8'>> err=<FDCapture 2 oldfd=7 _state='suspended' tmpfile=<EncodedFile name="<_io.FileIO name=8 mode='rb+' closefd=True>" mode='r+' encoding='utf-8'>> in_=<FDCapture 0 oldfd=3 _state='started' tmpfile=<_io.TextIOWrapper name='/dev/null' mode='r' encoding='utf-8'>> _state='suspended' _in_suspended=False> _capture_fixture=None>>,
 <HookImpl plugin_name='logging-plugin', plugin=<_pytest.logging.LoggingPlugin object at 0x7fc34fc08ec0>>,
 <HookImpl plugin_name='unraisableexception', plugin=<module '_pytest.unraisableexception' from '/usr/lib/python3.13/vendor-packages/_pytest/unraisableexception.py'>>,
 <HookImpl plugin_name='threadexception', plugin=<module '_pytest.threadexception' from '/usr/lib/python3.13/vendor-packages/_pytest/threadexception.py'>>]
        self       = <_pytest.config.PytestPluginManager object at 0x7fc352d40590>
/usr/lib/python3.13/vendor-packages/_pytest/threadexception.py:92: in pytest_runtest_call
    yield from thread_exception_runtest_hook()
/usr/lib/python3.13/vendor-packages/_pytest/threadexception.py:68: in thread_exception_runtest_hook
    yield
        cm         = <_pytest.threadexception.catch_threading_exception object at 0x7fc34ea0e210>
/usr/lib/python3.13/vendor-packages/_pytest/unraisableexception.py:95: in pytest_runtest_call
    yield from unraisable_exception_runtest_hook()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    def unraisable_exception_runtest_hook() -> Generator[None]:
        with catch_unraisable_exception() as cm:
            try:
                yield
            finally:
                if cm.unraisable:
                    if cm.unraisable.err_msg is not None:
                        err_msg = cm.unraisable.err_msg
                    else:
                        err_msg = "Exception ignored in"
                    msg = f"{err_msg}: {cm.unraisable.object!r}\n\n"
                    msg += "".join(
                        traceback.format_exception(
                            cm.unraisable.exc_type,
                            cm.unraisable.exc_value,
                            cm.unraisable.exc_traceback,
                        )
                    )
>                   warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E                   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <function IOBase.__del__ at 0x7fc35010e8e0>
E                   
E                   Traceback (most recent call last):
E                     File "/usr/lib/python3.13/_pyio.py", line 418, in __del__
E                       self.close()
E                       ~~~~~~~~~~^^
E                     File "/usr/lib/python3.13/_pyio.py", line 818, in close
E                       self.raw.close()
E                       ~~~~~~~~~~~~~~^^
E                     File "/usr/lib/python3.13/socket.py", line 789, in close
E                       self._sock._decref_socketios()
E                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E                   AttributeError: 'MockSocket' object has no attribute '_decref_socketios'

cm         = <_pytest.unraisableexception.catch_unraisable_exception object at 0x7fc34ea0f390>
err_msg    = 'Exception ignored in'
msg        = ('Exception ignored in: <function IOBase.__del__ at 0x7fc35010e8e0>\n'
 '\n'
 'Traceback (most recent call last):\n'
 '  File "/usr/lib/python3.13/_pyio.py", line 418, in __del__\n'
 '    self.close()\n'
 '    ~~~~~~~~~~^^\n'
 '  File "/usr/lib/python3.13/_pyio.py", line 818, in close\n'
 '    self.raw.close()\n'
 '    ~~~~~~~~~~~~~~^^\n'
 '  File "/usr/lib/python3.13/socket.py", line 789, in close\n'
 '    self._sock._decref_socketios()\n'
 '    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n'
 "AttributeError: 'MockSocket' object has no attribute '_decref_socketios'\n")

(test_bytes_written fails with pretty much the same one)

πŸ“‹ Environment

  • Cheroot version: tested with 10.0.0 and 11.0.0b3
  • Python version: 3.13.0
  • OS: Oracle Solaris (but this doesn't seem to be platform dependent)

πŸ“‹ Additional context

The following change fixed the issue for me:

--- cheroot-11.0.0b3/cheroot/test/test_makefile.py
+++ cheroot-11.0.0b3/cheroot/test/test_makefile.py
@@ -30,6 +30,9 @@ class MockSocket:
         """Simulate a send."""
         return len(val)
 
+    def _decref_socketios(self):
+        pass
+
 
 def test_bytes_read():
     """Reader should capture bytes read."""

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions