This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: _execvpe behaves inconsistently when PATH includes a filename
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 2.6
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: Oren_Held, r.david.murray
Priority: normal Keywords:

Created on 2010-05-02 15:03 by Oren_Held, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Messages (2)
msg104788 - (view) Author: Oren Held (Oren_Held) Date: 2010-05-02 15:03
A. Description
When running os._execvpe with a relative pathname that does not exist, I'd expect to get ENOENT error. But there is an edge case in which Python throws ENOTDIR error - when the LAST element in PATH is a regular file (e.g. /bin/ls). This case is caused by a sysadmin mistake, but it may happen, as in the system on which I've encountered this bug.

B. Explanation + How to reproduce:
Consider the following case:
PATH="/bin:/bin/ls" # Last part is a filename instead of a directory
>>> import os; os.execvp("blabla", [""])
Throws: OSError: [Errno 20] Not a directory

Now, consider a similar but differently-ordered PATH:
PATH="/bin/ls:/bin" # *First* part is a filename instead of a directory
>>> import os; os.execvp("blabla", [""])
Throws: OSError: [Errno 2] No such file or directory


C. Why this behavior is not good:
First, IMO there is a certain problem here - differently ordered PATH shouldn't throw different exception. In both cases the executable was not found in PATH, both cases are the same for this matter.

Second, the unix shell (e.g. bash) faces the same issue, and behaves differently. It'll return "command not found" to stdout for both ENOENT and ENOTDIR cases, regardless of the element order in PATH.


D. My recommendation
I'd recommend throwing ENOENT even when ENODIR is thrown for some paths. I am not sure what's the least-evil way to do it, I've been thinking of the following patch, but it's not working because it depends on strerror. It also looks kinda ugly:

--- os.py.old	2010-05-02 17:41:21.481909804 +0300
+++ os.py	2010-05-02 18:03:11.261872651 +0300
@@ -386,7 +386,7 @@
                 saved_tb = tb
     if saved_exc:
         raise error, saved_exc, saved_tb
-    raise error, e, tb
+    raise error, error(errno.ENOENT, os.strerror(errno.ENOENT)), tb # DOESNT WORK, no access to os.strerror from here
 
 # Change environ to automatically call putenv() if it exists
 try:
msg104789 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2010-05-02 16:10
The python functions are thin wrappers around the system calls, and are reporting the result of calling the corresponding system call.  The fact that the shell chooses to catch both errors and report a single one would be equivalent to, say, the cmd module doing something similar.  It would not be appropriate for the os module to combine the distinct errors into one.
History
Date User Action Args
2022-04-11 14:57:00adminsetgithub: 52845
2010-05-02 16:10:11r.david.murraysetstatus: open -> closed

nosy: + r.david.murray
messages: + msg104789

resolution: not a bug
stage: resolved
2010-05-02 15:03:59Oren_Heldsettitle: _execvpe should behaves inconsistently when PATH includes a filename -> _execvpe behaves inconsistently when PATH includes a filename
2010-05-02 15:03:44Oren_Heldcreate