Skip to content

Commit 0d14ec6

Browse files
achimnol1st1
authored andcommitted
fix: Accept path-like objects in subprocess arguments
* Also add subprocess test case using Path object * uvloop already handles path-like cwd correctly, so I just copy-and-pasted the same logic to _init_args() method. * The standard library uses "isinstance(obj, os.PathLike)" to check if an object is path-like, but os.PathLike exists as of Python 3.6. Since uvloop needs to support Python 3.5, we should use manual check for existence of the __fspath__ attribute. * According to the official Python documentation: - https://docs.python.org/3/library/subprocess.html#subprocess.Popen The subprocess.Popen() constructor support path-like objects since Python 3.6 on POSIX and since Python 3.8 on Windows. - https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.subprocess_exec This page does not mention about path-like objects, but as of Python 3.8, it DOES support path-like objects.
1 parent c392972 commit 0d14ec6

File tree

2 files changed

+22
-0
lines changed

2 files changed

+22
-0
lines changed

tests/test_process.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,21 @@ async def test():
135135

136136
self.loop.run_until_complete(test())
137137

138+
@unittest.skipIf(sys.version_info < (3, 8, 0),
139+
"3.5 to 3.7 does not support path-like objects "
140+
"in the asyncio subprocess API")
141+
def test_process_executable_2(self):
142+
async def test():
143+
proc = await asyncio.create_subprocess_exec(
144+
pathlib.Path(sys.executable),
145+
b'-W', b'ignore', b'-c', b'print("spam")',
146+
stdout=subprocess.PIPE)
147+
148+
out, err = await proc.communicate()
149+
self.assertEqual(out, b'spam\n')
150+
151+
self.loop.run_until_complete(test())
152+
138153
def test_process_pid_1(self):
139154
async def test():
140155
prog = '''\

uvloop/handles/process.pyx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,13 @@ cdef class UVProcess(UVHandle):
284284
self.__args = args.copy()
285285
for i in range(an):
286286
arg = args[i]
287+
try:
288+
fspath = type(arg).__fspath__
289+
except AttributeError:
290+
pass
291+
else:
292+
arg = fspath(arg)
293+
287294
if isinstance(arg, str):
288295
self.__args[i] = PyUnicode_EncodeFSDefault(arg)
289296
elif not isinstance(arg, bytes):

0 commit comments

Comments
 (0)