From 329f607ef027332e6b90fc5c63fcd34afdae851d Mon Sep 17 00:00:00 2001 From: Vizonex Date: Sat, 11 Jul 2026 14:21:44 -0500 Subject: [PATCH 1/2] bring back shlex parser due to shell related difficulties --- tests/test_process.py | 44 +++++++++++++++++++++++++++++++++++++ winloop/includes/stdlib.pxi | 4 ++++ winloop/loop.pyx | 17 +++++++++++--- 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/tests/test_process.py b/tests/test_process.py index b796491..db95a09 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -940,6 +940,50 @@ async def test(): class Test_UV_Process(_TestProcess, tb.UVTestCase): + @unittest.skipIf(sys.platform != "win32", "problem is windows related only") + def test_windows_issue_153(self): + """Winloop issue 153 is related to bringing back the shlex parser + which because there is a different system involved from regular + python subprocess's system to prevent the libuv library + from doing something worse and needing to change up more code. + + SEE: https://github.com/Vizonex/Winloop/issues/153 + """ + + async def test(): + CMD = 'python -c "import sys; print(\'hi\')"' + proc = await asyncio.create_subprocess_shell( + CMD, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + ) + + out, err = await proc.communicate() + assert out == b"hi\r\n" + assert err == b'' + assert proc.returncode == 0 + self.loop.run_until_complete(test()) + + @unittest.skipIf(sys.platform != "win32", "problem is windows related only") + def test_windows_issue_153_bytes(self): + """Winloop issue 153 is related to bringing back the shlex parser + which because there is a different system involved from regular + python subprocess's system to prevent the libuv library + from doing something worse and needing to change up more code.""" + async def test(): + CMD = b'python -c "import sys; print(\'hi\')"' + proc = await asyncio.create_subprocess_shell( + CMD, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + ) + out, err = await proc.communicate() + assert out == b"hi\r\n" + assert err == b'' + assert proc.returncode == 0 + self.loop.run_until_complete(test()) + + def test_process_double_close(self): script = textwrap.dedent(""" import os diff --git a/winloop/includes/stdlib.pxi b/winloop/includes/stdlib.pxi index 259842c..9ad7b02 100644 --- a/winloop/includes/stdlib.pxi +++ b/winloop/includes/stdlib.pxi @@ -18,6 +18,7 @@ import subprocess import ssl import stat import sys +import shlex import threading import traceback import time @@ -101,6 +102,7 @@ cdef int socket_EAI_PROTOCOL = getattr(socket, 'EAI_PROTOCOL', -1) cdef int socket_EAI_SERVICE = getattr(socket, 'EAI_SERVICE', -1) cdef int socket_EAI_SOCKTYPE = getattr(socket, 'EAI_SOCKTYPE', -1) +cdef shlex_split = shlex.split cdef str os_name = os.name cdef os_path_isabs = os.path.isabs @@ -119,6 +121,7 @@ cdef os_remove = os.remove cdef os_stat = os.stat cdef os_unlink = os.unlink cdef os_fspath = os.fspath +cdef os_fsdecode = os.fsdecode cdef stat_S_ISSOCK = stat.S_ISSOCK @@ -181,3 +184,4 @@ del asyncio, concurrent, collections, errno del functools, inspect, itertools, socket, os, threading del signal, subprocess, ssl del time, traceback, warnings, weakref +del shlex diff --git a/winloop/loop.pyx b/winloop/loop.pyx index cb8686a..32472ea 100644 --- a/winloop/loop.pyx +++ b/winloop/loop.pyx @@ -120,6 +120,10 @@ cdef inline run_in_context2(context, method, arg1, arg2): # *reuse_address* parameter _unset = object() +cdef list split_windows_shell_command(object cmd): + if isinstance(cmd, bytes): + cmd = cmd.decode("utf-8", "surrogateescape") + return shlex_split(cmd) @cython.no_gc_clear cdef class Loop: @@ -2834,9 +2838,16 @@ cdef class Loop: if not os_path_isabs(comspec): raise FileNotFoundError('shell not found: neither %ComSpec% nor %SystemRoot% is set') - args = [comspec] - args.append('/c') - args.append(cmd) + args = [comspec, b'/c'] + + # XXX: We don't want to change more code than what is + # currently required and supporting bytes is better + # than windows stdlib (subprocesses.Popen disallows bytes) + # so a small workaround with the shlex parser was needed. + # Originally it was removed but brought back. + # SEE: https://github.com/Vizonex/Winloop/issues/153 + + args.extend(split_windows_shell_command(cmd)) return await self.__subprocess_run(protocol_factory, args, shell=True, **kwargs) From 2ca6903b229559101a294d826ce695ced5a9e8af Mon Sep 17 00:00:00 2001 From: Vizonex Date: Sat, 11 Jul 2026 14:32:16 -0500 Subject: [PATCH 2/2] pre-commit fix --- tests/test_process.py | 6 +++--- winloop/loop.pyx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_process.py b/tests/test_process.py index db95a09..c7be41e 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -946,7 +946,7 @@ def test_windows_issue_153(self): which because there is a different system involved from regular python subprocess's system to prevent the libuv library from doing something worse and needing to change up more code. - + SEE: https://github.com/Vizonex/Winloop/issues/153 """ @@ -957,13 +957,13 @@ async def test(): stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, ) - + out, err = await proc.communicate() assert out == b"hi\r\n" assert err == b'' assert proc.returncode == 0 self.loop.run_until_complete(test()) - + @unittest.skipIf(sys.platform != "win32", "problem is windows related only") def test_windows_issue_153_bytes(self): """Winloop issue 153 is related to bringing back the shlex parser diff --git a/winloop/loop.pyx b/winloop/loop.pyx index 32472ea..96a5262 100644 --- a/winloop/loop.pyx +++ b/winloop/loop.pyx @@ -2839,12 +2839,12 @@ cdef class Loop: raise FileNotFoundError('shell not found: neither %ComSpec% nor %SystemRoot% is set') args = [comspec, b'/c'] - - # XXX: We don't want to change more code than what is + + # XXX: We don't want to change more code than what is # currently required and supporting bytes is better # than windows stdlib (subprocesses.Popen disallows bytes) # so a small workaround with the shlex parser was needed. - # Originally it was removed but brought back. + # Originally it was removed but brought back. # SEE: https://github.com/Vizonex/Winloop/issues/153 args.extend(split_windows_shell_command(cmd))