I wrote a program that reads a text file and runs an .exe for every line in the text file. This results in opening a new command line window for every time i run the .exe. The windows do close on their own once the current task is finished, but the problem is as follows:
If i have 100 lines in the text file, this means that i call the .exe file 100 times. My problem with that is if i want to cancel the run after it already started, i have to click on the red "X" to close every window one after the another.
What i am trying to do is have some sort of a command interrupt the running program and either close all upcoming windows or just stop the for loop from running.
Is it possible to write into the console a command to interrupt the current running code?
Would it be better to use some sort of a key event listener? If so, are there any built-in key listeners in Python? I can't seem to find any. Does that mean that i have to install Pygame just so i can use a key event listener?
Maybe i should try to listen to the command line and detect an exit code on one of the windows that i manually close and that way end the for loop?
There are a few ways you could go about this. But pretty much you have one main issue - you need some sort of flag that can be switched such that the code will know it must stop. For instance, if the code is working in a while-loop, it should check at the start of this loop if the flag is valid, or if the flag is telling the loop to stop...
while flag:
# do code
There are a few ways to implement this flagging like operation for your needs. I will discuss the threading option. First, you need to understand how threading works, and then you need to mold your script such that instead of "running an executable" for each line of the text file, you would read the text file, and put all the lines into a queue, then you would have a few threads that read from that queue, and perform the desired action (like running an executable) but instead of running an external executable, you should mimick this with Python, this thread should be a daemon thread.. and it should have a main loop which checks if a flag that exists in the parent thread is turned on...
Below is an example:
from threading import Thread
from Queue import Queue
import sys
import time
class Performer():
def __init__(self):
self.active = False
self.queue = Queue()
def action(self, line):
pass # your code should be here
def operate(self, text_file, threads=5):
with open(text_file) as f:
for line in f:
self.queue.put(line)
self.active = True
thread_pool = []
for i in range(threads):
t = Thread(target=self.__thread, name=('worker-%d' % i))
t.daemon = True
t.start()
thread_pool.append(t)
while self.active:
try:
if self.queue.empty():
break
except KeyboardInterrupt:
self.active = False
sys.exit('user + keyboard = byebye')
else:
time.sleep(1)
def __thread(self):
while self.active:
if not self.queue.empty():
try:
self.action(self.queue.get())
except Exception:
pass # do something here
Related
Im trying to lock the volume of the sonos using SoCo in a webapp. I need to run a separate script to do this. So when the user presses the lock button it runs a loop constantly setting the volume to the value until the program gets called or toggled stopping it.
I need this done in a different script as if its in the main code i'm unable to get any user input to unlock it.
#app.route("/lock")
def lock():
run(togglelock.py)
return "ok"
#togglelock.py
toggle("F","T")
sound1 = (sonos.volume)
if toggle == "T":
sonos1.volume = sound1
else:
break
As long as the other python file is in the same directory, you can simply import it when you want to run it.
def lock():
import togglelock
return "ok"
#do more stuff....
I am trying to write a small clipboard logger (for linux) that listens for an event (the change of the clipboard content) and writes the clipboard content to a file (on-change).
What I have come up with is a simple while loop with the clipboard module pyperclip:
import pyperclip
recent_value = ""
while True:
tmp_value = pyperclip.paste()
if tmp_value != recent_value:
recent_value = tmp_value
with open(".clipboard_history.txt", "a") as f:
f.write(recent_value + "\n")
So my first question is, can I actually run a while True loop to 'listen' or will this consume too much memory or be generally inefficient or bad practice?
And the second question is, how can I run this in the background like a shell job control (ampersand)?
Should I go for a daemon like suggested here or some kind of event loop or threading magic?
I basically want something that sits in the background and listens for an event (clipboard content changes), reacts on it (writes to a file) and waits again.
============================
edit: Thanks for the input! + new question: Would I still need the sleep method if I used threading?
Running your current loop will drain CPU, import from time, and use time.sleep(1) or something else that would put the program to sleep for a little while (ideally 0.1-2~ seconds if you think they would be swapping copy/paste fast)
You don't need to thread if this is all your program is going to be doing.
First of all, you need to fix your indentation as the following:
while True:
tmp_value = pyperclip.paste()
if tmp_value != recent_value:
recent_value = tmp_value
with open(".clipboard_history.txt", "a") as f:
f.write(recent_value + "\n")
Now if your script has more code, and you want this loop to keep running in the background, you can use threading and define a function for the loop:
from threading import Thread
t = Thread(target=your-func, args=[])
t.start()
def your-func(self):
# your loop goes here
So my first question is, can I actually run a while True loop to
'listen' or will this consume too much memory or be generally
inefficient or bad practice?
It is inefficient. You probably want to add at the end of your loop
time.sleep(0.1)
Better practice would be to run your script every time clipboard is being written to. This discussion is also relevant to you: Trigger an event when clipboard content changes
And the second question is, how can I run this in the background like
a shell job control (ampersand)?
Refer to here.
To run a python file with no console the extension should be .pyw, for example when running logger.pyw it will be ran without opening a python shell.
Hope this answered your question.
I wrote a little code which scans the wifi signals in the air and according to the amount plays one or another audio file.
import time
import subprocess
import os
while True:
output = subprocess.Popen("airport en1 -s", shell=True, stdout=subprocess.PIPE).stdout.read()
lines = output.split('\n')
n = len(lines)
if n < 10:
print os.path.exists('/Users/shirin/Desktop/wifi/1.mp3')
p = subprocess.Popen(['/Applications/VLC.app/Contents/MacOS/VLC','/Users/shirin/Desktop/wifi/1.mp3'])
elif n > 10:
print os.path.exists('/Users/shirin/Desktop/wifi/1.mp3')
p = subprocess.Popen(['/Applications/VLC.app/Contents/MacOS/VLC','/Users/shirin/Desktop/wifi/1.mp3'])
Now my problem is that, when I run the file through the terminal it keeps running the code over and over again and I do not know how to stop it. It also does not stop when I close the terminal.
So my question:
How can I tell python to run the code once and then stop?
already super thanks!
Two things:
You have a while True: and no condition to break the loop, insert a break after reproducing the audio file so the loop could stop.
Even if you close the program VLC would be running until you manually stop it. This is because you are just calling an external command. If you want to reproduce the audio from python you can use another library like pygame
You can call p.terminate() if you want to terminate your application.
You can also call p.kill() if your application is not responsive.
Now, let's say you want to stop the application and stop VLC.
Have except KeyboardInterrupt: in your code and call p.terminate() when you stop the script.
while True:
try:
... #code goes here.
except KeyboardInterrupt:
p.terminate()
I have a thread that monitors user input which looks like this:
def keyboard_monitor(temp): #temp is sys.stdin
global flag_exit
while True:
keyin = temp.readline().rstrip().lower()
if keyin == "exit":
flag_exit = True
print("Stopping...")
if flag_exit == True:
break
If I type exit the flag is properly set and all the other threads terminate. If another one of my threads sets the flag, this thread refuses to finish because it's hanging on the user input. I have to input something to get it to finish. How do I change this code so that the program finishes when the flag is set externally?
Its hard to tell exactly what is going wrong without more of your code, but as an easy solution you could rather exit() which is a python built in. This should reliably terminate the application, also sys.exit()
From wim's comment:
You can use the atexit module to register clean up handlers
import atexit
def cleanup():
pass
# TODO cleanup
atexit.register(cleanup)
I have a script runReports.py that is executed every night. Suppose for some reason the script takes too long to execute, I want to be able to stop it from terminal by issuing a command like ./runReports.py stop.
I tried to implement this by having the script to create a temporary file when the stop command is issued.
The script checks for existence of this file before running each report.
If the file is there the script stops executing, else it continues.
But I am not able to find a way to make the issuer of the stop command aware that the script has stopped successfully. Something along the following lines:
$ ./runReports.py stop
Stopping runReports...
runReports.py stopped successfully.
How to achieve this?
For example if your script runs in loop, you can catch signal http://en.wikipedia.org/wiki/Unix_signal and terminate process:
import signal
class SimpleReport(BaseReport):
def __init__(self):
...
is_running = True
def _signal_handler(self, signum, frame):
is_running = False
def run(self):
signal.signal(signal.SIGUSR1, self._signal_handler) # set signal handler
...
while is_running:
print("Preparing report")
print("Exiting ...")
To terminate process just call kill -SIGUSR1 procId
You want to achieve inter process communication. You should first explore the different ways to do that : system V IPC (memory, very versatile, possibly baffling API), sockets (including unix domain sockets)(memory, more limited, clean API), file system (persistent on disk, almost architecture independent), and choose yours.
As you are asking about files, there are still two ways to communicate using files : either using file content (feature rich, harder to implement), or simply file presence. But the problem using files, is that is a program terminates because of an error, it may not be able to write its ended status on the disk.
IMHO, you should clearly define what are your requirements before choosing file system based communication (testing the end of a program is not really what it is best at) unless you also need architecture independence.
To directly answer your question, the only reliable way to know if a program has ended if you use file system communication is to browse the list of currently active processes, and the simplest way is IMHO to use ps -e in a subprocess.
Instead of having a temporary file, you could have a permanent file(config.txt) that has some tags in it and check if the tag 'running = True'.
To achieve this is quiet simple, if your code has a loop in it (I imagine it does), just make a function/method that branches a check condition on this file.
def continue_running():
with open("config.txt") as f:
for line in f:
tag, condition = line.split(" = ")
if tag == "running" and condition == "True":
return True
return False
In your script you will do this:
while True: # or your terminal condition
if continue_running():
# your regular code goes here
else:
break
So all you have to do to stop the loop in the script is change the 'running' to anything but "True".