Home > Back-end >  Use subprocess.Popen non-interactively
Use subprocess.Popen non-interactively

Time:08-16

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).

CodePudding user response:

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.

CodePudding user response:

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()
  • Related