The Python Oracle

Test if executable exists in Python?

--------------------------------------------------
Hire the world's top talent on demand or became one of them at Toptal: https://topt.al/25cXVn
and get $2,000 discount on your first invoice
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Drifting Through My Dreams

--

Chapters
00:00 Test If Executable Exists In Python?
00:26 Accepted Answer Score 337
01:09 Answer 2 Score 21
02:11 Answer 3 Score 389
02:20 Answer 4 Score 275
03:19 Thank you

--

Full question
https://stackoverflow.com/questions/3770...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #path

#avk47



ANSWER 1

Score 389


Python stdlib now offers shutil.which.




ACCEPTED ANSWER

Score 337


Easiest way I can think of:

def which(program):
    import os
    def is_exe(fpath):
        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)

    fpath, fname = os.path.split(program)
    if fpath:
        if is_exe(program):
            return program
    else:
        for path in os.environ.get("PATH", "").split(os.pathsep):
            exe_file = os.path.join(path, program)
            if is_exe(exe_file):
                return exe_file

    return None

Edit: Updated code sample to include logic for handling case where provided argument is already a full path to the executable, i.e. "which /bin/ls". This mimics the behavior of the UNIX 'which' command.

Edit: Updated to use os.path.isfile() instead of os.path.exists() per comments.

Edit: path.strip('"') seems like the wrong thing to do here. Neither Windows nor POSIX appear to encourage quoted PATH items.




ANSWER 3

Score 275


Use shutil.which() from Python's wonderful standard library.

Documented as

Return the path to an executable which would be run if the given cmd was called. If no cmd would be called, return None.

import shutil

path = shutil.which("foo") 

if path is None:
    print("no executable found for command 'foo'")
else:
    print(f"path to executable 'foo': {path}")

Benefits over home-cooked solutions: documentation, interface stability, long-term maintenance. I advocated for this solution here ~10 years ago, and just one month ago (April 2023), a few relevant details improved again under the hood of this high-level interface provided by excellent engineers doing the hard work for you. Batteries included 🔋!

By the way, the name is indeed derived from the famous which command on Unix-like systems (and the pedantic POSIX person says: "never use which cmd, use command -v cmd, it's more portable") :-).




ANSWER 4

Score 21


Just remember to specify the file extension on windows. Otherwise, you have to write a much complicated is_exe for windows using PATHEXT environment variable. You may just want to use FindPath.

OTOH, why are you even bothering to search for the executable? The operating system will do it for you as part of popen call & will raise an exception if the executable is not found. All you need to do is catch the correct exception for given OS. Note that on Windows, subprocess.Popen(exe, shell=True) will fail silently if exe is not found.


Incorporating PATHEXT into the above implementation of which (in Jay's answer):

def which(program):
    def is_exe(fpath):
        return os.path.exists(fpath) and os.access(fpath, os.X_OK) and os.path.isfile(fpath)

    def ext_candidates(fpath):
        yield fpath
        for ext in os.environ.get("PATHEXT", "").split(os.pathsep):
            yield fpath + ext

    fpath, fname = os.path.split(program)
    if fpath:
        if is_exe(program):
            return program
    else:
        for path in os.environ["PATH"].split(os.pathsep):
            exe_file = os.path.join(path, program)
            for candidate in ext_candidates(exe_file):
                if is_exe(candidate):
                    return candidate

    return None