2

My issue is similar to How to run Python's subprocess and leave it in background , however none of answers listed there worked for me.

I try to run a program, for example Slack or Discord (or other programs listed in question updates). I want program to run even if my script finishes.

I need this to work on Windows.

Note: the issue happen only when Slack / Discord is started from Python script, if it was running before, then it isn't closed.

Example code: (as you can see I tried multiple ways):

import os, subprocess
from time import sleep
from subprocess import Popen, PIPE, STDOUT

# discord_path=r"C:\Program Files\Discord\Discord.exe"
# discord_path2=r"C:\Users\user\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Discord Inc\Discord.lnk"
# os.startfile(discord_path2)

# subprocess.run([r"C:\Users\user\AppData\Local\Discord\Update.exe", "--processStart", "Discord.exe"],shell=True)
# subprocess.Popen([r"C:\Users\user\AppData\Local\Discord\Update.exe", "--processStart", "Discord.exe"],shell=True)
# subprocess.call([r"C:\Users\user\AppData\Local\Discord\Update.exe", "--processStart", "Discord.exe"])
# subprocess.Popen([r"C:\Users\user\AppData\Local\Discord\Update.exe", "--processStart", "Discord.exe"], stdin=None, stdout=None, stderr=None, close_fds=True)

# slack_path2=r"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Slack Technologies Inc\Slack.lnk"
# os.startfile(slack_path2)
#  stdin=None, stdout=None, stderr=None, 

# subprocess.Popen([r"C:\Program Files\Slack\slack.exe", "--startup"], close_fds=True)

proc = Popen([r"C:\Program Files\Slack\slack.exe", "--startup"], stdout=PIPE, stderr=STDOUT)

sleep(5)
# now program (Slack / Discord) is exited and I can't prevent it

Update: I tested also notepad.exe, calc.exe and winver.

notepad.exe and winver behave the same as Slack and Discord. However calc.exe stays opened after script finishes (so this program is behaves exceptional).

Code:

subprocess.Popen(['notepad.exe'])
subprocess.Popen(['calc.exe'])
subprocess.Popen(['winver'])

Update 2: I need to run a few programs this way (including both Slack and Discord), so using os.execl() won't do the job, because it quits python script immediately.

Update 3: As I put in one of comments, it turned out that I was running python from within vscode, and vscode was somehow closing processes after main Python script finished. When I run Python script from Powershell then most answers below work as desired.

Karol Zlot
  • 2,887
  • 2
  • 20
  • 37
  • What is the reason for usin `stdout=PIPE` if the program is expected to survive your script? – Serge Ballesta Mar 11 '22 at 14:22
  • @SergeBallesta It's here, because I tried any solution I was able to find, without it it also didn't work as desired. – Karol Zlot Mar 11 '22 at 14:25
  • 1
    It is weird. I have just tried this code with `notepad.exe` (I do not use discord), and the notepad window stays correctly opened after the end of the Python script. Could you try using notepad to make sure whether the problem is related to your Python installation or to discord. – Serge Ballesta Mar 11 '22 at 14:32
  • `subprocess.Popen(['notepad.exe'])` seems to work in that notepad remains open after the script has terminated. – JonSG Mar 11 '22 at 14:39
  • @SergeBallesta @JonSG I updated my question. `subprocess.Popen(['notepad.exe'])` didn't work for me, but with `calc.exe` it did. – Karol Zlot Mar 11 '22 at 14:50
  • Yes, if run in vscode, it will kill the whole thing, but open works fine running from shell – Hairy Ass Jul 02 '22 at 07:20

5 Answers5

4

You should use os.spawn*() function to create new process

Here's your example:

We run the program at the path with the nonblocking flag os.P_NOWAIT

The last two arguments are given to the process. (yeah, if you're not familiar, the first argument should be the path of the program, by which it's called, and then your arguments, for more info google 'argv')

import os

path = r"C:\Program Files\Slack\slack.exe"
os.spawnl(os.P_NOWAIT,        # flag
          path,               # programm
          path, "--startup")  # arguments

print("Bye! Now it's your responsibility to close new process :0")
0dminnimda
  • 1,242
  • 3
  • 12
  • 29
  • @Karol if this answer helped you or you like it, please do not forget to [vote up and mark the answer as a solution](https://stackoverflow.com/help/someone-answers), I would really appreciate it. – 0dminnimda Mar 11 '22 at 14:43
  • 1
    I'm sorry, but... your solution also didn't work . I tested for both Slack and Discord. Both programs closed after `sleep(5)` – Karol Zlot Mar 11 '22 at 14:48
  • Whatever the function used to start a new process, be it `os.system`, `os.spawn`, or `subprocess.*`, the new process will be a direct child of the Python interpretor, and in the Windows OS, it will be created via `CreateProcess`. On a Unix or Unix-like system it would be created via `fork` and `exec`. So unsure whether it could be useful for OP, but the first sentence is wrong. – Serge Ballesta Mar 11 '22 at 14:49
  • @KarolZlot try [`os.execl`](https://docs.python.org/3/library/os.html#os.execl) if you don't need to do anything in python after the new process is started – 0dminnimda Mar 11 '22 at 14:52
  • @0dminnimda I need to run a few programs like this and only then quit python script. However `os.execl()` seems to exit python script immediately. – Karol Zlot Mar 11 '22 at 14:57
  • It works after all. See "Update 3" in question. – Karol Zlot Mar 11 '22 at 16:33
3

It turned out that I just needed to run Python script not from vscode, but for example from Powershell.

Karol Zlot
  • 2,887
  • 2
  • 20
  • 37
2

As I use neither discord not slack I could not test anything. But I would try to use the process creation flags to break as many links as possible between the new process and the Python program:

from subprocess import Popen, CREATE_NEW_PROCESS_GROUP, DETACHED_PROCESS

proc = Popen([r"C:\Program Files\Slack\slack.exe", "--startup"],
             creationflags=CREATE_NEW_PROCESS_GROUP|DETACHED_PROCESS)
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
1

The solution is actually easier then it seemed :]
We can just use os.popen to run command in cmd/pipe, this will make those processes not dependent on the python process! So let's just do it:

import os

os.popen("notepad.exe")
os.popen("notepad.exe")

print("Bye! Now it's your responsibility to close new process(es) :0")

this served as my inspiration, tho this solution works a little differently


Windows-only:

Also if you don't want to run several Popen's (through os.popen) to open one cmd.exe and use it instead:

import subprocess
from time import sleep

path = r"C:\Windows\System32\cmd.exe"
p = subprocess.Popen(
    [path],
    bufsize=-1,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    stdin=subprocess.PIPE)


def comunicate(process, message):
    process.stdin.write(message)
    process.stdin.flush()


comunicate(p, b'notepad.exe\n')
comunicate(p, b'notepad.exe\n')

sleep(0.1)
comunicate(p, b'exit\n')  # closes cmd

print("Bye! Now it's your responsibility to close new process :0")
0dminnimda
  • 1,242
  • 3
  • 12
  • 29
  • @KarolZlot posting the second answer as it's a different approach and edititng the first one doesn't work for me because of the comments, but now this should work, I tested it! – 0dminnimda Mar 11 '22 at 16:21
  • I just tested it and... it still doesn't work . – Karol Zlot Mar 11 '22 at 16:25
  • But all the time I was testing from vscode (F5). When I now tried running from PowerShell, then it started working as desired (I see that other answers also work.... ) – Karol Zlot Mar 11 '22 at 16:25
  • It works after all. See "Update 3" in question. – Karol Zlot Mar 11 '22 at 16:33
  • 1
    @KarolZlot it'll be really nice if you'd accepted the best answers a solution. As it seems `os.popen` is the most elegant way ;3 – 0dminnimda Mar 11 '22 at 16:39
0

you should be able to run the program as a command and not a subprocess. you'll need to excecute a command using the os.system(*your command*) function. you'll have to import it with import os

That way it should launch the program seperate and not in a subprocess

  • 2
    this executes the command in the subshell and this is also blocking function, meaning python script won't be able to do anything but wait until the process is ended – 0dminnimda Mar 11 '22 at 14:18
  • As @0dminnimda said, it isn't working as desired. – Karol Zlot Mar 11 '22 at 14:59