From 0003a0238f7e5635ff00885c4d5bbe5382fafe3b Mon Sep 17 00:00:00 2001 From: AN Long Date: Mon, 4 Aug 2025 23:50:04 +0900 Subject: [PATCH 01/14] Add unix domain socket for Windows --- Lib/test/test_socket.py | 6 +++++- Modules/socketmodule.c | 2 ++ Modules/socketmodule.h | 3 +++ PC/pyconfig.h | 3 +++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 3dd67b2a2aba97..d8094cda10ff95 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -5131,7 +5131,7 @@ def __init__(self, methodName='runTest'): def _check_defaults(self, sock): self.assertIsInstance(sock, socket.socket) - if hasattr(socket, 'AF_UNIX'): + if sys.platform != 'win32' and hasattr(socket, 'AF_UNIX'): self.assertEqual(sock.family, socket.AF_UNIX) else: self.assertEqual(sock.family, socket.AF_INET) @@ -6188,6 +6188,8 @@ def bind(self, sock, path): else: raise + @unittest.skipIf(sys.platform == 'win32', + 'Windows will raise Error if is not bound') def testUnbound(self): # Issue #30205 (note getsockname() can return None on OS X) self.assertIn(self.sock.getsockname(), ('', None)) @@ -6227,6 +6229,8 @@ def testUnencodableAddr(self): @unittest.skipIf(sys.platform in ('linux', 'android'), 'Linux behavior is tested by TestLinuxAbstractNamespace') + @unittest.skipIf(sys.platform == 'win32', + 'Windows allow bind on empty path') def testEmptyAddress(self): # Test that binding empty address fails. self.assertRaises(OSError, self.sock.bind, "") diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index f3ad01854de93b..967a097b8651f4 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -334,6 +334,8 @@ typedef struct { /* IMPORTANT: make sure the list ordered by descending build_number */ static FlagRuntimeInfo win_runtime_flags[] = { + /* available starting with Windows 10 1803 */ + {17134, "AF_UNIX"}, /* available starting with Windows 10 1709 */ {16299, "TCP_KEEPIDLE"}, {16299, "TCP_KEEPINTVL"}, diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h index 7fd929af5f27b4..b566d34a462d09 100644 --- a/Modules/socketmodule.h +++ b/Modules/socketmodule.h @@ -94,8 +94,11 @@ typedef int socklen_t; # include #endif /* MS_WINDOWS */ +#define HAVE_AFUNIX_H 1 #ifdef HAVE_SYS_UN_H # include +#elif HAVE_AFUNIX_H +# include #else # undef AF_UNIX #endif diff --git a/PC/pyconfig.h b/PC/pyconfig.h index 0e8379387cd025..c1212de445948c 100644 --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -671,6 +671,9 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ /* Define if you have the header file. */ /* #define HAVE_SYS_UN_H 1 */ +/* Define if you have the header file. */ +#define HAVE_AFUNIX_H 1 + /* Define if you have the header file. */ /* #define HAVE_SYS_UTIME_H 1 */ From 2eb7917f4906e444cc4990bfcf9e59ce712e276c Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 5 Aug 2025 00:48:28 +0900 Subject: [PATCH 02/14] Skip some tests on socketserver test --- Lib/test/test_socketserver.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Lib/test/test_socketserver.py b/Lib/test/test_socketserver.py index 0f62f9eb200e42..e165f4e0f409df 100644 --- a/Lib/test/test_socketserver.py +++ b/Lib/test/test_socketserver.py @@ -8,6 +8,7 @@ import select import signal import socket +import sys import threading import unittest import socketserver @@ -218,18 +219,24 @@ def test_ForkingUDPServer(self): self.dgram_examine) @requires_unix_sockets + @unittest.skipIf(sys.platform=="win32", + "Unix with Dadagram is not supported on Windows") def test_UnixDatagramServer(self): self.run_server(socketserver.UnixDatagramServer, socketserver.DatagramRequestHandler, self.dgram_examine) @requires_unix_sockets + @unittest.skipIf(sys.platform=="win32", + "Unix with Dadagram is not supported on Windows") def test_ThreadingUnixDatagramServer(self): self.run_server(socketserver.ThreadingUnixDatagramServer, socketserver.DatagramRequestHandler, self.dgram_examine) @requires_unix_sockets + @unittest.skipIf(sys.platform=="win32", + "Unix with Dadagram is not supported on Windows") @requires_forking def test_ForkingUnixDatagramServer(self): self.run_server(socketserver.ForkingUnixDatagramServer, From 49a71497fc252a4fa4e4ae1d3d16efb01879723f Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 5 Aug 2025 23:56:16 +0900 Subject: [PATCH 03/14] Fix more tests --- Lib/test/test_asyncio/test_base_events.py | 2 ++ Lib/test/test_asyncio/test_events.py | 5 +++++ Lib/test/test_asyncio/utils.py | 8 ++++++++ Lib/test/test_pathlib/test_pathlib.py | 1 + Lib/test/test_stat.py | 1 + 5 files changed, 17 insertions(+) diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py index 8c02de77c24740..34d96dd1025b81 100644 --- a/Lib/test/test_asyncio/test_base_events.py +++ b/Lib/test/test_asyncio/test_base_events.py @@ -1939,6 +1939,8 @@ def test_create_datagram_endpoint_sock(self): self.assertEqual('CLOSED', protocol.state) @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'No UNIX Sockets') + @unittest.skipIf(sys.platform == 'win32', 'AF_UNIX support for asyncio is ' + 'not implemented on Windows for now') def test_create_datagram_endpoint_sock_unix(self): fut = self.loop.create_datagram_endpoint( lambda: MyDatagramProto(create_future=True, loop=self.loop), diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index 919d543b0329e9..5fc9556f9920f1 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -1035,6 +1035,9 @@ def test_create_server_reuse_port(self): server.close() def _make_unix_server(self, factory, **kwargs): + if sys.platform == 'win32': + raise unittest.SkipTest('AF_UNIX support for asyncio is not ' + 'implemented on Windows for now') path = test_utils.gen_unix_socket_path() self.addCleanup(lambda: os.path.exists(path) and os.unlink(path)) @@ -1072,6 +1075,8 @@ def test_create_unix_server(self): server.close() @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'No UNIX Sockets') + @unittest.skipIf(sys.platform == 'win32', 'AF_UNIX support for asyncio is ' + 'not implemented on Windows for now') def test_create_unix_server_path_socket_error(self): proto = MyProto(loop=self.loop) sock = socket.socket() diff --git a/Lib/test/test_asyncio/utils.py b/Lib/test/test_asyncio/utils.py index a480e16e81bb91..05010b89929d69 100644 --- a/Lib/test/test_asyncio/utils.py +++ b/Lib/test/test_asyncio/utils.py @@ -200,6 +200,8 @@ def app(environ, start_response): if hasattr(socket, 'AF_UNIX'): class UnixHTTPServer(socketserver.UnixStreamServer, HTTPServer): + if sys.platform == 'win32': + allow_reuse_address = False def server_bind(self): socketserver.UnixStreamServer.server_bind(self) @@ -243,6 +245,9 @@ def gen_unix_socket_path(): @contextlib.contextmanager def unix_socket_path(): + if sys.platform == 'win32': + raise unittest.SkipTest('AF_UNIX support for asyncio is not ' + 'implemented on Windows for now') path = gen_unix_socket_path() try: yield path @@ -255,6 +260,9 @@ def unix_socket_path(): @contextlib.contextmanager def run_test_unix_server(*, use_ssl=False): + if sys.platform == 'win32': + raise unittest.SkipTest('AF_UNIX support for asyncio is not ' + 'implemented on Windows for now') with unix_socket_path() as path: yield from _run_test_server(address=path, use_ssl=use_ssl, server_cls=SilentUnixWSGIServer, diff --git a/Lib/test/test_pathlib/test_pathlib.py b/Lib/test/test_pathlib/test_pathlib.py index a1105aae6351b6..e925f4f8508d86 100644 --- a/Lib/test/test_pathlib/test_pathlib.py +++ b/Lib/test/test_pathlib/test_pathlib.py @@ -2747,6 +2747,7 @@ def test_is_socket_false(self): @unittest.skipIf( is_wasi, "Cannot create socket on WASI." ) + @unittest.skipIf(sys.platform=='win32', "didn't work on Windows") def test_is_socket_true(self): P = self.cls(self.base, 'mysock') sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) diff --git a/Lib/test/test_stat.py b/Lib/test/test_stat.py index 5fd25d5012c425..1f17177b4c5b3f 100644 --- a/Lib/test/test_stat.py +++ b/Lib/test/test_stat.py @@ -215,6 +215,7 @@ def test_devices(self): break @socket_helper.skip_unless_bind_unix_socket + @unittest.skipIf(sys.platform=='win32', "didn't work on Windows") def test_socket(self): with socket.socket(socket.AF_UNIX) as s: s.bind(TESTFN) From e1c5ceb0c84cd72ffa94bed740d488c67f0fe049 Mon Sep 17 00:00:00 2001 From: AN Long Date: Wed, 6 Aug 2025 00:27:49 +0900 Subject: [PATCH 04/14] Detect if we have AF_UNIX header --- .../next/Windows/2025-08-05-23-59-59.gh-issue-77589.soytRy.rst | 1 + PC/pyconfig.h | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Windows/2025-08-05-23-59-59.gh-issue-77589.soytRy.rst diff --git a/Misc/NEWS.d/next/Windows/2025-08-05-23-59-59.gh-issue-77589.soytRy.rst b/Misc/NEWS.d/next/Windows/2025-08-05-23-59-59.gh-issue-77589.soytRy.rst new file mode 100644 index 00000000000000..8fa31e146e8bb2 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2025-08-05-23-59-59.gh-issue-77589.soytRy.rst @@ -0,0 +1 @@ +Add Unix domain socket on Windows. Patched by AN Long. diff --git a/PC/pyconfig.h b/PC/pyconfig.h index c1212de445948c..6fc834755266e5 100644 --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -672,7 +672,9 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ /* #define HAVE_SYS_UN_H 1 */ /* Define if you have the header file. */ +#if defined(NTDDI_WIN10_RS4) && (NTDDI_VERSION >= NTDDI_WIN10_RS4) #define HAVE_AFUNIX_H 1 +#endif /* Define if you have the header file. */ /* #define HAVE_SYS_UTIME_H 1 */ From 175a96e34924cc4ce81ad0cd8b1e8fdbcf439d1b Mon Sep 17 00:00:00 2001 From: AN Long Date: Wed, 6 Aug 2025 00:34:18 +0900 Subject: [PATCH 05/14] Suppress compiler warning --- Modules/socketmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 967a097b8651f4..752040096aee86 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -1902,7 +1902,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, addr->sun_path[path.len] = 0; /* including the tailing NUL */ - *len_ret = path.len + offsetof(struct sockaddr_un, sun_path) + 1; + *len_ret = (int)path.len + offsetof(struct sockaddr_un, sun_path) + 1; } addr->sun_family = s->sock_family; memcpy(addr->sun_path, path.buf, path.len); From a70f8346fcc1a297f907c481afb9cdbc4be9e8d5 Mon Sep 17 00:00:00 2001 From: AN Long Date: Wed, 6 Aug 2025 01:12:26 +0900 Subject: [PATCH 06/14] Fix test in mp module --- Lib/test/_test_multiprocessing.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index a1259ff1d63d18..8582f2a8a97efc 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -5536,11 +5536,6 @@ def test_invalid_family(self): with self.assertRaises(ValueError): multiprocessing.connection.Listener(r'\\.\test') - @unittest.skipUnless(WIN32, "skipped on non-Windows platforms") - def test_invalid_family_win32(self): - with self.assertRaises(ValueError): - multiprocessing.connection.Listener('/var/test.pipe') - # # Issue 12098: check sys.flags of child matches that for parent # From 5f93fbbe9c87443071a885c0b0db4e7c3537548d Mon Sep 17 00:00:00 2001 From: AN Long Date: Wed, 6 Aug 2025 23:06:03 +0900 Subject: [PATCH 07/14] Disable reuse_address in http.server on Windows with AF_UNIX --- Lib/http/server.py | 6 ++++++ Lib/test/test_asyncio/utils.py | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/http/server.py b/Lib/http/server.py index a2ffbe2e44df64..5a6e515c101d7d 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -117,6 +117,12 @@ class HTTPServer(socketserver.TCPServer): allow_reuse_address = True # Seems to make sense in testing environment allow_reuse_port = False + def __init__(self, *args, **kwargs): + if sys.platform == 'win32' and self.address_family == socket.AF_UNIX: + self.allow_reuse_address = False + + super().__init__(*args, **kwargs) + def server_bind(self): """Override server_bind to store the server name.""" socketserver.TCPServer.server_bind(self) diff --git a/Lib/test/test_asyncio/utils.py b/Lib/test/test_asyncio/utils.py index 05010b89929d69..9f9913aec077d7 100644 --- a/Lib/test/test_asyncio/utils.py +++ b/Lib/test/test_asyncio/utils.py @@ -200,8 +200,6 @@ def app(environ, start_response): if hasattr(socket, 'AF_UNIX'): class UnixHTTPServer(socketserver.UnixStreamServer, HTTPServer): - if sys.platform == 'win32': - allow_reuse_address = False def server_bind(self): socketserver.UnixStreamServer.server_bind(self) From c759ee74321d5dc956947da185f44b4f753c0301 Mon Sep 17 00:00:00 2001 From: AN Long Date: Wed, 6 Aug 2025 23:14:38 +0900 Subject: [PATCH 08/14] Fix build on wasi --- Modules/socketmodule.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h index b566d34a462d09..2edc704405f447 100644 --- a/Modules/socketmodule.h +++ b/Modules/socketmodule.h @@ -94,7 +94,6 @@ typedef int socklen_t; # include #endif /* MS_WINDOWS */ -#define HAVE_AFUNIX_H 1 #ifdef HAVE_SYS_UN_H # include #elif HAVE_AFUNIX_H From 7ce46a7f983f4027a0df0ec2affd5566b45f48b0 Mon Sep 17 00:00:00 2001 From: AN Long Date: Thu, 7 Aug 2025 02:06:59 +0900 Subject: [PATCH 09/14] Fix build --- PC/pyconfig.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/PC/pyconfig.h b/PC/pyconfig.h index 6fc834755266e5..c1212de445948c 100644 --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -672,9 +672,7 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ /* #define HAVE_SYS_UN_H 1 */ /* Define if you have the header file. */ -#if defined(NTDDI_WIN10_RS4) && (NTDDI_VERSION >= NTDDI_WIN10_RS4) #define HAVE_AFUNIX_H 1 -#endif /* Define if you have the header file. */ /* #define HAVE_SYS_UTIME_H 1 */ From 4d4562421d3cb29a933d5787c6e4a8e6ccba4de8 Mon Sep 17 00:00:00 2001 From: AN Long Date: Fri, 8 Aug 2025 00:54:29 +0900 Subject: [PATCH 10/14] Fix test in logging --- Lib/http/server.py | 4 +++- Lib/test/test_logging.py | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Lib/http/server.py b/Lib/http/server.py index 5a6e515c101d7d..5d51008e382001 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -118,7 +118,9 @@ class HTTPServer(socketserver.TCPServer): allow_reuse_port = False def __init__(self, *args, **kwargs): - if sys.platform == 'win32' and self.address_family == socket.AF_UNIX: + if sys.platform == 'win32' and hasattr(socket, 'AF_UNIX') and\ + self.address_family == socket.AF_UNIX: + # reuse address with AF_UNIX is not supported on Windows self.allow_reuse_address = False super().__init__(*args, **kwargs) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 275f7ce47d09b5..e5339b861d4273 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -2089,6 +2089,8 @@ def test_output(self): self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m') def test_udp_reconnection(self): + if self.server_exception: + self.skipTest(self.server_exception) logger = logging.getLogger("slh") self.sl_hdlr.close() self.handled.clear() From fb216528aee9a1317fa2b564c2c6e5619c7ee2e8 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 9 Aug 2025 00:28:37 +0900 Subject: [PATCH 11/14] Skip testSurrogateescapeBind on Windows --- Lib/test/test_socket.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index d8094cda10ff95..fdd9efbca0618a 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -6208,6 +6208,8 @@ def testBytesAddr(self): self.addCleanup(os_helper.unlink, path) self.assertEqual(self.sock.getsockname(), path) + @unittest.skipIf(sys.platform == 'win32', + 'surrogateescape file path is not supported on Windows') def testSurrogateescapeBind(self): # Test binding to a valid non-ASCII pathname, with the # non-ASCII bytes supplied using surrogateescape encoding. From 510ef3ffe08c48796f505f1321bd05d3e50d08af Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 9 Aug 2025 23:30:52 +0900 Subject: [PATCH 12/14] Skip another test --- Lib/test/test_socket.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index fdd9efbca0618a..079058544e7f2e 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -6219,6 +6219,9 @@ def testSurrogateescapeBind(self): self.addCleanup(os_helper.unlink, path) self.assertEqual(self.sock.getsockname(), path) + @unittest.skipIf(sys.platform == 'win32', + 'Windows have a bug which can\'t unlink sock file with ' + 'TESTFN_UNENCODABLE in it\'s name') def testUnencodableAddr(self): # Test binding to a pathname that cannot be encoded in the # file system encoding. From dd07aecac839198f00d5ed7c48d16c2e146f9c40 Mon Sep 17 00:00:00 2001 From: AN Long Date: Mon, 11 Aug 2025 22:35:25 +0900 Subject: [PATCH 13/14] Update tests --- Lib/test/test_pathlib/test_pathlib.py | 22 +++++++++++++++++++++- Lib/test/test_socket.py | 11 +++++++++++ Lib/test/test_stat.py | 9 +++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_pathlib/test_pathlib.py b/Lib/test/test_pathlib/test_pathlib.py index e925f4f8508d86..a4a08dcf1ddc32 100644 --- a/Lib/test/test_pathlib/test_pathlib.py +++ b/Lib/test/test_pathlib/test_pathlib.py @@ -2747,7 +2747,8 @@ def test_is_socket_false(self): @unittest.skipIf( is_wasi, "Cannot create socket on WASI." ) - @unittest.skipIf(sys.platform=='win32', "didn't work on Windows") + @unittest.skipIf(sys.platform=='win32', + "detecting if file is socket is not supported by Windows") def test_is_socket_true(self): P = self.cls(self.base, 'mysock') sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) @@ -2764,6 +2765,25 @@ def test_is_socket_true(self): self.assertIs(self.cls(self.base, 'mysock\udfff').is_socket(), False) self.assertIs(self.cls(self.base, 'mysock\x00').is_socket(), False) + @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required") + @unittest.skipUnless(sys.platform=='win32', + "socket file on Windows is a normal file") + def test_is_socket_on_windows(self): + P = self.cls(self.base, 'mysock') + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.addCleanup(sock.close) + try: + sock.bind(str(P)) + except OSError as e: + if (isinstance(e, PermissionError) or + "AF_UNIX path too long" in str(e)): + self.skipTest("cannot bind Unix socket: " + str(e)) + self.assertFalse(P.is_socket()) + self.assertFalse(P.is_fifo()) + self.assertTrue(P.is_file()) + self.assertIs(self.cls(self.base, 'mysock\udfff').is_socket(), False) + self.assertIs(self.cls(self.base, 'mysock\x00').is_socket(), False) + def test_is_block_device_false(self): P = self.cls(self.base) self.assertFalse((P / 'fileA').is_block_device()) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 079058544e7f2e..9e406cda60048f 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -6194,6 +6194,11 @@ def testUnbound(self): # Issue #30205 (note getsockname() can return None on OS X) self.assertIn(self.sock.getsockname(), ('', None)) + @unittest.skipUnless(sys.platform == 'win32', + 'Windows-specific behavior') + def test_unbound_on_windows(self): + self.assertRaisesRegex(OSError, 'WinError 10022', self.sock.getsockname) + def testStrAddr(self): # Test binding to and retrieving a normal string pathname. path = os.path.abspath(os_helper.TESTFN) @@ -6240,6 +6245,12 @@ def testEmptyAddress(self): # Test that binding empty address fails. self.assertRaises(OSError, self.sock.bind, "") + @unittest.skipUnless(sys.platform == 'win32', + 'Windows-specified behavior') + def test_empty_address_on_windows(self): + self.sock.bind('') + self.assertEqual(self.sock.getsockname(), '') + class BufferIOTest(SocketConnectedTest): """ diff --git a/Lib/test/test_stat.py b/Lib/test/test_stat.py index 1f17177b4c5b3f..4a7113cf2fe175 100644 --- a/Lib/test/test_stat.py +++ b/Lib/test/test_stat.py @@ -223,6 +223,15 @@ def test_socket(self): self.assertEqual(modestr[0], 's') self.assertS_IS("SOCK", st_mode) + @socket_helper.skip_unless_bind_unix_socket + @unittest.skipUnless(sys.platform=='win32', "didn't work on Windows") + def test_socket_on_windows(self): + with socket.socket(socket.AF_UNIX) as s: + s.bind(TESTFN) + st_mode, modestr = self.get_mode() + self.assertNotEqual(modestr[0], 's') + self.assertS_IS("REG", st_mode) + def test_module_attributes(self): for key, value in self.stat_struct.items(): modvalue = getattr(self.statmod, key) From 9c68464dce8cdf2c423387a3b10d70503ad3c722 Mon Sep 17 00:00:00 2001 From: AN Long Date: Mon, 11 Aug 2025 23:58:00 +0900 Subject: [PATCH 14/14] Using __has_include to detect header files --- PC/pyconfig.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/PC/pyconfig.h b/PC/pyconfig.h index c1212de445948c..300acf6aaf368c 100644 --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -672,7 +672,11 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ /* #define HAVE_SYS_UN_H 1 */ /* Define if you have the header file. */ -#define HAVE_AFUNIX_H 1 +#if defined(__has_include) && __has_include() + #define HAVE_AFUNIX_H 1 +#else + #define HAVE_AFUNIX_H 0 +#endif /* Define if you have the header file. */ /* #define HAVE_SYS_UTIME_H 1 */