Alex W.'s Blog

Supporting CLI programs in `subprocess.run` on macOS & Windows without `shell=True`

In Windows, subprocess.run uses CreateProcess (docs) which (appears to?) only identify .exe files by default. Therefore when trying to run something like the heroku CLI using subprocess.run('heroku') it fails with [WinError 2] The system cannot find the file specified. Using where heroku I can see that it has two executables at:

C:\Program Files\heroku\bin\heroku
C:\Program Files\heroku\bin\heroku.cmd

Using shell=True fixes this because the shell (cmd.exe /c) resolves these paths, while CreateProcess doesn’t. However, I can resolve these using another Python tool and avoid introducing the security issues and overhead of shell=True by using the shutil.which method (docs).

Combined, the full command would be:

subprocess.run(shutil.which('heroku'))