Skip to content

Commit

Permalink
fix: Accept path-like objects in subprocess arguments
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
achimnol authored and 1st1 committed May 16, 2020
1 parent c392972 commit 0d14ec6
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 0 deletions.
15 changes: 15 additions & 0 deletions tests/test_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,21 @@ async def test():

self.loop.run_until_complete(test())

@unittest.skipIf(sys.version_info < (3, 8, 0),
"3.5 to 3.7 does not support path-like objects "
"in the asyncio subprocess API")
def test_process_executable_2(self):
async def test():
proc = await asyncio.create_subprocess_exec(
pathlib.Path(sys.executable),
b'-W', b'ignore', b'-c', b'print("spam")',
stdout=subprocess.PIPE)

out, err = await proc.communicate()
self.assertEqual(out, b'spam\n')

self.loop.run_until_complete(test())

def test_process_pid_1(self):
async def test():
prog = '''\
Expand Down
7 changes: 7 additions & 0 deletions uvloop/handles/process.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,13 @@ cdef class UVProcess(UVHandle):
self.__args = args.copy()
for i in range(an):
arg = args[i]
try:
fspath = type(arg).__fspath__
except AttributeError:
pass
else:
arg = fspath(arg)

if isinstance(arg, str):
self.__args[i] = PyUnicode_EncodeFSDefault(arg)
elif not isinstance(arg, bytes):
Expand Down

0 comments on commit 0d14ec6

Please sign in to comment.