2

I'm trying to build a todo manager in python where I want to continuously run a process in the bg that will alert the user with a popup when the specified time comes. I'm wondering how I can achieve that. I've looked at some of the answers on StackOverflow and on other sites but none of them really helped. So, What I want to achieve is to start a bg process once the user enters a task and keep on running it in the background until the time comes. At the same time there might be other threads running for other tasks as well that will end at their end times.

So far, I've tried this:

t = Thread(target=bg_runner, kwargs={'task': task, 'lock_file': lock_file_path})
t.setName("Get Done " + task.
t.start()
t.join()

With this the thread is continuosly running but it runs in the foreground and only exits when the execution is done.

If I add t.daemon = True in the above code, the main thread immediately exits after start() and it looks like the daemon is also getting killed then.

Please let me know how this can be solved.

Durga Swaroop
  • 563
  • 1
  • 6
  • 25
  • How are you running this application? You also don't need to use threads to keep the process running in the background, but instead you mean consider using a `while True:` loop. – JJK Dec 11 '17 at 19:03
  • @JJK I'm running it as a python script. I'm already doing a `while` in the `bg_runner` method that I've put as `target` in the code snippet I've added. I want to run it in the background completely. How would running just the `while` loop solve this? – Durga Swaroop Dec 11 '17 at 19:07
  • Generally speaking, threading is not recommended in Python. See this answer about how you can do that using multiprocessing module: https://stackoverflow.com/questions/47577391/python-calling-method-over-multiple-instances-parallelly/47577661#47577661 – Amit Tripathi Dec 11 '17 at 19:10
  • @AmitTripathi I looked at that answer but I still don't see how I can apply to my current problem. And yes I'm starting to realize that threading is a bit of an issue in python. – Durga Swaroop Dec 11 '17 at 19:16
  • @DurgaSwaroop You can run your program in the background using multiprocess module(also look at `subprocess` module). You can do whatever you are doing with thread in multiprocess module. – Amit Tripathi Dec 11 '17 at 19:21
  • Running a script in the background is less of a problem - [`nohup`](http://linux.101hacks.com/unix/nohup-command/) can deal with that - the bigger issue is did you plan how will you control it once you send it to the background and where do you imagine it should run popups? – zwer Dec 11 '17 at 19:44
  • @zwer The background thread/process will basically just wait till a particular time and then show a popup using qt. Although `nohup` does it, I would like it to be handled by the program itself if possible. – Durga Swaroop Dec 11 '17 at 19:57

2 Answers2

1

I'm guessing that you just don't want to see the terminal window after you launch the script. In this case, it is a matter of how you execute the script.

Try these things.

If you are using a windows computer you can try using pythonw.exe:

pythonw.exe example_script.py

If you are using linux (maybe OSx) you may want to use 'nohup' in the terminal.

nohup python example_script.py


More or less the reason you have to do this comes down to how the Operating system handles processes. I am not an expert on this subject matter, but generally if you launch a script from a terminal, that script becomes a child process of the terminal. So if you exit that terminal, it will also terminate any child processes. The only way to get around that is to either detach the process from the terminal with something like nohup.

Now if you end up adding the #!/usr/bin/env python shebang line, your os could possibly just run the script without a terminal window if you just double click the script. YMMV (Again depends on how your OS works)

JJK
  • 808
  • 8
  • 8
  • This is what I am doing for now as a temporary solution but I'm looking for a way to handle this in the code itself. It is very weird to think python doesn't have a better way of doing this. – Durga Swaroop Dec 11 '17 at 19:26
  • As a scripting language you need to execute the code in some fashion. And ultimately it comes down to how the operating system manages hierarchical processes. If you have finalized code an want to deploy it as an executable you may want to consider using something like pyinstaller (http://www.pyinstaller.org/) and passing the --noconsole flag. So whenever you run the app, it just runs in the background. – JJK Dec 11 '17 at 19:32
  • My application requires some user input via console. Can I still use pyinstaller for that? – Durga Swaroop Dec 11 '17 at 19:37
  • Depends on what kind of user input. If its something they can input before they launch the script you can add it as an argument. executable_name arg1 arg2. But if you are prompting for a password or at specific moments of the script then it may require additional steps. – JJK Dec 11 '17 at 19:41
  • Out of curiosity what OS are you using so I can answer more specifically? – JJK Dec 11 '17 at 19:42
  • I'm using windows but I run it on git bash. And as I said it is basically a todo list manager. So, the inputs can't be given all at once. – Durga Swaroop Dec 11 '17 at 19:56
1

The first thing you need to do is prevent your script from exiting by adding a while loop in the main thread:

import time
from threading import Thread

t = Thread(target=bg_runner, kwargs={'task': task, 'lock_file': lock_file_path})
t.setName("Get Done " + task)
t.start()
t.join()
while True:
    time.sleep(1.0)

Then you need to put it in the background:

$ nohup python alert_popup.py >> /dev/null 2>&1 &

You can get more information on controlling a background process at this answer.