You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Support path-like objects in shutil.which() #161788
shutil.which() accepts a bytes command and returns a bytes path. It also accepts path-like command objects, but a path-like object whose __fspath__() method returns bytes raises TypeError instead of behaving like the equivalent direct bytes value.
On CPython main, the first call returns a bytes path and the second fails:
b'/usr/bin/python3'
TypeError: Can't mix strings and bytes in path components
which() checks whether cmd is bytes before resolving the path-like object. It then decodes PATH to str, while os.path.split() has resolved the command to bytes. Calling os.fspath(cmd) before choosing the string or bytes path keeps the command and search path on the same type.
I don't think it's a bug. It accepts path-like objects by change I think, not by contract. Supporting bytes was a new feature because it also returned bytes. But looking at older issues, it's not clear whether shutil.which() should support path-like objects (see #90883, #67430 as well)
Oh right, hadn't considered that path-like support might be accidental. I was thinking the return type could follow whatever os.fspath() returns, but I do see your point.
Do you think it's worth supporting that, or should we leave path-like commands unsupported?
Considering how hard it was for adding the bytes support, I'd rather not add pathlike support. I'd prefer that every functions that seems to work with pathlike in shutil to be considered accidental and decide later whether to add pathlike support entirely or not. Semantically, it's a bit hard to determine whether cmd should be considered a path or not in the first place (e.g., shutil.which('ls') returns a path but this doesn't mean that the command itself should be a path).
Activity
picnixz commentedon Nov 11, 2026
I don't think it's a bug. It accepts path-like objects by change I think, not by contract. Supporting bytes was a new feature because it also returned bytes. But looking at older issues, it's not clear whether shutil.which() should support path-like objects (see #90883, #67430 as well)
[-]shutil.which() fails for bytes-backed path-like commands[/-][+]Support path-like objects in shutil.which() [/+]Builder106 commentedon Nov 11, 2026
@picnixz
Oh right, hadn't considered that path-like support might be accidental. I was thinking the return type could follow whatever
os.fspath()returns, but I do see your point.Do you think it's worth supporting that, or should we leave path-like commands unsupported?
picnixz commentedon Nov 11, 2026
Considering how hard it was for adding the bytes support, I'd rather not add pathlike support. I'd prefer that every functions that seems to work with pathlike in shutil to be considered accidental and decide later whether to add pathlike support entirely or not. Semantically, it's a bit hard to determine whether
cmdshould be considered a path or not in the first place (e.g.,shutil.which('ls')returns a path but this doesn't mean that the command itself should be a path).