skip to Main Content

I’m trying to non-interactively execute a git pull command with subprocess.Popen. Specifically, if for some reason git asks for a password, the command should fail. But instead, it asks the password in the shell I run my python program in, and waits for my input, this not what I want.

I also need to capture the output of the command (this is why I use subprocess.Popen). I have noted that if I use stdout = DEVNULL then it behaves as I want, excepted I do need to pipe stdout to capture it.

Here is a simplified version of the code I use to execute the command:

from subprocess import Popen, PIPE, STDOUT, DEVNULL

process = Popen(['git', 'clone', 'https://some-url.git'], stdin = DEVNULL, stdout = PIPE)

for line in process.stdout:
    print(line.decode())

process.wait()

I’ve also tried with stdin = None. This parameter seems to have no effect.

I’m executing the python program in a bash console on a Debian 11 system (but I’d like a portable solution).

2

Answers


  1. Chosen as BEST ANSWER

    I've found a way to deal with this issue, by using setsid to run the command in a non-interactive session. But this is a Linux thing, I'm still interested if there is a way to solve the issue with python in a portable way (I haven't made any test on Windows yet, maybe the issue doesn't exist there to begin with, but surely setsid won't work).

    The code would look like this:

    from subprocess import Popen, PIPE, STDOUT, DEVNULL
    
    process = Popen(['setsid', 'git', 'clone', 'https://some-url.git'], stdout = PIPE)
    
    for line in process.stdout:
        print(line.decode())
    
    process.wait()
    

  2. Why are you redirecting errors to STDOUT if you don’t want to show the output? For it to end up on the stdout filehandle of the process object, you want PIPE, but if you don’t care what it is, just send it to DEVNULL.

    Tangentially, you should avoid the bare Popen when what you want can be accomplished with subprocess.run or subprocess.check_output.

    output = subprocess.check_output(
        ['git', 'clone', 'https://some-url.git'],
        # perhaps
        stdin=DEVNULL, stderr=DEVNULL)
    

    shell=False is already the default, so you don’t need to specify that.

    check_output will raise an error if the git command fails; you might want to wrap that in try/except, or perhaps revert to subprocess.run which gives you more control over these details.

    Tangentially, perhaps note that git may separately run ssh and generate error output from that e.g. when you connect to a host you have not connected to before. The sustainable solution to that is to specify options for how to handle the connection, perhaps in your .ssh/config.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search