diff --git a/news/2718.behavior b/news/2718.behavior new file mode 100644 index 0000000000..c00b1d4696 --- /dev/null +++ b/news/2718.behavior @@ -0,0 +1 @@ +Fallback to shell mode if `run` fails with Windows error 193 to handle non-executable commands. This should improve usability on Windows, where some users run non-executable files without specifying a command, relying on Windows file association to choose the current command. diff --git a/pipenv/core.py b/pipenv/core.py index 31adf6998e..8e56adb1d0 100644 --- a/pipenv/core.py +++ b/pipenv/core.py @@ -2091,15 +2091,31 @@ def inline_activate_virtual_environment(): os.environ["VIRTUAL_ENV"] = root -def do_run_nt(script): +def _launch_windows_subprocess(script): import subprocess command = system_which(script.command) options = {"universal_newlines": True} - if command: # Try to use CreateProcess directly if possible. - p = subprocess.Popen([command] + script.args, **options) - else: # Command not found, maybe this is a shell built-in? - p = subprocess.Popen(script.cmdify(), shell=True, **options) + + # Command not found, maybe this is a shell built-in? + if not command: + return subprocess.Popen(script.cmdify(), shell=True, **options) + + # Try to use CreateProcess directly if possible. Specifically catch + # Windows error 193 "Command is not a valid Win32 application" to handle + # a "command" that is non-executable. See pypa/pipenv#2727. + try: + return subprocess.Popen([command] + script.args, **options) + except WindowsError as e: + if e.winerror != 193: + raise + + # Try shell mode to use Windows's file association for file launch. + return subprocess.Popen(script.cmdify(), shell=True, **options) + + +def do_run_nt(script): + p = _launch_windows_subprocess(script) p.communicate() sys.exit(p.returncode)