Update UnixSocketMixin to disable socket cleanup on Py >= 3.13#592
Update UnixSocketMixin to disable socket cleanup on Py >= 3.13#592cuu508 wants to merge 5 commits into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #592 +/- ##
==========================================
+ Coverage 97.75% 97.81% +0.05%
==========================================
Files 23 23
Lines 5709 5712 +3
Branches 351 352 +1
==========================================
+ Hits 5581 5587 +6
+ Misses 79 75 -4
- Partials 49 50 +1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
2707444 to
7eda3d4
Compare
Starting from Python 3.13, the unix listener automatically cleans up its socket from the filesystem on shutdown. This can be disabled by passing in cleanup_socket=False. I think it makes sense for aiosmtpd to do that, to keep the shutdown behavior consistent between Python versions. This change fixes the only failing test on Python 3.13: aiosmtpd/tests/test_server.py::TestUnthreaded::test_unixsocket
Passing *kw to `create_unix_server` works at runtime but I'm not sure how to annotate it correctly. Added "type: ignore" to silence mypy warning about unrecognized cleanup_socket argument: python/typeshed#15742
74918fa to
95b926f
Compare
For some unclear reason, if: * tests are run on python 3.13 * and the system has a proper, non-loopback IPv6 address * and inside tests we mock the socket.recv() function then `asyncio.base_events.Server._wakeup` gets called twice and throws an exception on the second call. As a workaround, in test_controller.py, mock something adjacent to socket.recv – the socket.create_connection function.
webknjaz
left a comment
There was a problem hiding this comment.
I think the overall approach is fine as a compatibility fix. But long-term, it may make sense to flip the behavior down the line. Or at least provide a way to opt into this behavior and/or have a CM interface for this.
In general, I'd expect servers to clean garbage they've produced, upon completion.
| return self.loop.create_unix_server( | ||
| self._factory_invoker, | ||
| path=self.unix_socket, | ||
| ssl=self.ssl_context, |
There was a problem hiding this comment.
It'd be cleaner to have
| ssl=self.ssl_context, | |
| **_create_unix_server_trailing_kwargs, |
and compute the var conditionally with {} for older versions.
There was a problem hiding this comment.
IIRC I initially tried that but couldn't make mypy happy.
What do these changes do?
This change fixes the only failing test on Python 3.13:
This test starts an Unix listener, exercises it, closes it and checks if the socket still exists on the filesystem. The socket does exist on Python 3.12 and below (the test passes), but does not exist on Python 3.13 (the test fails).
This is because Python added automatic socket cleanup: python/cpython#111246
There's a new
cleanup_socket=Falseargument forcreate_unix_serverwhich restores the old behavior (docs). I think it makes sense for aiosmtpd to use it, to keep the shutdown behavior consistent between Python versions.Are there changes in behavior for the user?
Yes:
There's no change when using Python 3.12 and below.
Related issue number
Checklist
NEWS.rstfile