Jesse Aldridge
Jesse Aldridge

Reputation: 8149

Make subprocess find git executable on Windows

import subprocess

proc = subprocess.Popen('git status')
print 'result: ', proc.communicate()

I have git in my system path, but when I run subprocess like this I get:
WindowsError: [Error 2] The system cannot find the file specified

How can I get subprocess to find git in the system path?

Python 2.6 on Windows XP.

Upvotes: 13

Views: 8210

Answers (4)

VonC
VonC

Reputation: 1326782

Note that in 2020, with With Git 2.28 (Q3 2020), Python 2.6 or older is no longer supported.

See commit 45a87a8 (07 Jun 2020) by Denton Liu (Denton-L).
(Merged by Junio C Hamano -- gitster -- in commit 6361eb7, 18 Jun 2020)

CodingGuidelines: specify Python 2.7 is the oldest version

Signed-off-by: Denton Liu

In 0b4396f068 ("git-p4: make python2.7 the oldest supported version", 2019-12-13, Git v2.27.0-rc0 -- merge listed in batch #1), git-p4 was updated to only support 2.7 and newer. Since Python 2.6 is pretty much ancient history, update CodingGuidelines to show that 2.7 is the oldest version supported.

Upvotes: 0

aknuds1
aknuds1

Reputation: 68067

The problem you see here is that the Windows API function CreateProcess, used by subprocess under the hood, doesn't auto-resolve other executable extensions than .exe. On Windows, the 'git' command is really installed as git.cmd. Therefore, you should modify your example to explicitly invoke git.cmd:

import subprocess

proc = subprocess.Popen('git.cmd status')
print 'result: ', proc.communicate()

The reason git works when shell==True is that the Windows shell auto-resolves git to git.cmd.

Eventually, resolve git.cmd yourself:

import subprocess
import os.path

def resolve_path(executable):
    if os.path.sep in executable:
        raise ValueError("Invalid filename: %s" % executable)

    path = os.environ.get("PATH", "").split(os.pathsep)
    # PATHEXT tells us which extensions an executable may have
    path_exts = os.environ.get("PATHEXT", ".exe;.bat;.cmd").split(";")
    has_ext = os.path.splitext(executable)[1] in path_exts
    if not has_ext:
        exts = path_exts
    else:
        # Don't try to append any extensions
        exts = [""]

    for d in path:
        try:
            for ext in exts:
                exepath = os.path.join(d, executable + ext)
                if os.access(exepath, os.X_OK):
                    return exepath
        except OSError:
            pass

    return None

git = resolve_path("git")
proc = subprocess.Popen('{0} status'.format(git))
print 'result: ', proc.communicate()

Upvotes: 12

user193476
user193476

Reputation:

You mean

proc = subprocess.Popen(["git", "status"], stdout=subprocess.PIPE)

The first argument of subprocess.Popen takes a shlex.split-like list of arguments.

or:

proc = subprocess.Popen("git status", stdout=subprocess.PIPE, shell=True)

This is not recommended, as you are launching a shell then launching a process in the shell.

Also, you should use stdout=subprocess.PIPE to retrieve the result.

Upvotes: 0

jdd
jdd

Reputation: 4336

I believe you need to pass env in to Popen, something like:

import subprocess, os
proc = subprocess.Popen('git status', env=os.environ, stdout=subprocess.PIPE)

Should do the trick.

Upvotes: -2

Related Questions