i'm trying to build personal assistant which is running by voice command.it is working perfectly with if: elif: blocks. but i want to create more elegance way and shorten code a bit.i try to create modular structure but i cant manage to terminate running function by calling middleman function with command=false parameter
i need some guiding please
main.py
from handler import middleman
while True:
message = input("> ")
if message != "":
middleman(message) #lets say command is "play1" than next command "play2"
Handler.py
from music import Class1
from music import Class2
def func1(context, command):
if command == True:
x = Class1(context)
x.run()
else:
x.stop() --> x not exist here gives error
def func2(context, command):
if command == True:
x = Class2(context)
x.run()
else:
x.stop()
def middleman(text):
command = True
if text == "stop":
command = False
function_name = globals()[text]
function_name(command)
music.py
import logging
import threading
import time
import pygame
class Player(threading.Thread):
def __init__(self, file_path, volume=1.0, start_time=0.0, master=None):
print("player started")
threading.Thread.__init__(self)
# 传入主窗口的指针,用于触发主窗口事件(若有)
self.master = master
self.file_path = file_path
# 音乐播放起点
self.start_time = start_time
# 用于控制音乐播放与停止
self.stop_state = False
# 用于控制音乐的暂停和恢复
self.pause_state = False
# 控制默认音量
self.volume = volume
# 初始化mixer
pygame.mixer.init() # 初始化音频
self.track = pygame.mixer.music
def set_volume(self, volume):
self.volume = volume
self.track.set_volume(self.volume)
def get_volume(self):
return self.volume
def run(self,stop):
print("stop word,stop")
try:
file = self.file_path
self.track.load(file) # 载入音乐文件
self.track.set_volume(self.volume) # 设置音量
self.track.play(start=self.start_time) # 开始播放
except Exception as e:
logging.warning(e)
if self.master:
self.master.event_generate("<<MusicError>>", when="tail")
while self.stop_state:
time.sleep(1)
# 若停止播放或播放结束,则结束这个线程
if self.stop_state:
self.track.stop() # 停止播放
return
elif not self.track.get_busy():
if self.master:
self.master.event_generate("<<CouldMusicStop>>", when="tail")
return
elif not self.stop_state and self.pause_state:
self.track.pause() # 暂停播放
elif not self.stop_state and not self.pause_state:
self.track.unpause() # 恢复播放
def stop(self):
self.stop_state=True
self.player = None
I am trying to make a simple audio player with the ability to play, stop, pause and resume songs.
What I am trying to do
Run the audio on a separate thread with the ability to then use MCI from the main thread to pause and resume it.
What doesn't work
When trying to call a function to play a song using threading or multiprocessing MCI returns an error code with a value of 263 (unfortunately there is no documentation about number error codes anywhere online that i've been able to find) and instantly ends the whole program.
What does work
Playing, pausing and resuming without the use of threading/multiprocessing.
My code
from ctypes import windll
import threading
import time
class WinPlayAudio():
def __init__(self):
self.alias = "A{}".format(id(self))
def _MCI_command(self,command):
windll.winmm.mciSendStringW(command,0,0,0) # If printed, this returns 263 == unrecognized audio device
# This does not play anything even tho wait is turned to: True
def _play(self, start=0, wait = False):
th = threading.Thread(target=self._MCI_command, args=(f'play {self.alias} from {start} {"wait" if wait else ""}',))
th.start()
def _open_song(self, audio_path):
self._MCI_command(f'open {audio_path} alias {self.alias}')
def _set_volume(self):
self._MCI_command(f'setaudio {self.alias} volume to 500')
def _pause(self):
self._MCI_command(f'pause {self.alias}')
def _resume(self):
self._MCI_command(f'resume {self.alias}')
def _stop(self):
self._MCI_command(f'stop {self.alias}')
if __name__ == '__main__':
p = WinPlayAudio()
p._open_song(r"D:\songs\bee.mp3")
p._play(0, True)
Fixed Code
Stay away from aliasing if you wish to multithread
import threading
from ctypes import windll
class WinPlayAudio():
def __init__(self):
self.alias = "A{}".format(id(self))
self.audio_path = ""
def _MCI_command(self, command):
print(command)
err = windll.winmm.mciSendStringW(command, 0, 0, 0) # If printed, this returns 263 == unrecognized audio device
print(err)
def _play(self, start=0, wait=True):
th = threading.Thread(target=self.__play__, args=(start, wait))
th.start()
def __play__(self, start, wait):
self._MCI_command(f'play {self.audio_path} from {start} {"wait" if wait else ""}', )
def _open_song(self, audio_path):
self.audio_path = audio_path
self._MCI_command(f'open {audio_path} alias {self.alias}')
def _set_volume(self):
self._MCI_command(f'setaudio {self.alias} volume to 500')
def _pause(self):
self._MCI_command(f'pause {self.alias}')
def _resume(self):
self._MCI_command(f'resume {self.alias}')
def _stop(self):
self._MCI_command(f'stop {self.alias}')
if __name__ == '__main__':
p = WinPlayAudio()
p._open_song("start.mp3")
p._play()
I am trying to create multiple threads of bot and they share some variables, but I am failing miserably in getingt the shared variables to work.
Here is the code:
import requests
import sys
import threading
import signal
import time
class bot(threading.Thread):
terminate = False
#def __init__(self):
# threading.Thread.__init__(self)
# self.terminate = False
def getCode():
code_lock.acquire()
work_code = code
try:
code += 1
finally:
code_lock.release()
return work_code
def checkCode(code):
try:
#if(code % 1000000 == 0):
print("Code "+str(code)+" is being checked...\n")
html = requests.get(url+str(code))
html.encoding = 'utf-8'
return not 'Page Not Found' in html.text
except requests.exceptions.ConnectionError:
print("Connection Error! Retrying...\n")
time.sleep(0.5)
except KeyboardInterrupt:
logCode(code)
sys.exit()
def storeCode(code):
file_lock.acquire()
try:
file.write(code+'\n')
finally:
file_lock.release()
def logCode(code):
log_lock.acquire()
try:
log.write(code+'\n')
finally:
log_lock.release()
#def run(self):
# global bots
# global url
# global file
# global log
# global code_lock
# global file_lock
# global log_lock
while(not terminate):
code = getCode()
if(checkCode(code)):
storeCode(code)
logCode(code)
def main(code = 0, threads = 16):
#bots = [threading.Thread(target=bot) for bot in range(threads)]
bots = []
url = 'https://test.ing/codes/'
file = open("valid-codes.txt", "a")
log = open("log.txt", "a")
code_lock = threading.Lock()
file_lock = threading.Lock()
log_lock = threading.Lock()
def signal_handler(signal, frame):
print('Exiting...\n')
log_lock.acquire()
try:
log.write("\n\n"+str(time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime()))+"\n")
finally:
log_lock.release()
for bot in bots:
bot.terminate = True
for bot in bots:
bot.join()
sys.exit(0)
#for bot in bots:
# bot.start()
for i in range(threads):
t = bot()
bots.append(t)
t.start()
signal.signal(signal.SIGINT, signal_handler)
while True:
signal.pause()
main(736479509787350, 1)
With this code I get this error:
Traceback (most recent call last): File "bot.py", line 7, in
class bot(threading.Thread): File "bot.py", line 59, in bot
code = getCode() File "bot.py", line 14, in getCode
code_lock.acquire() NameError: name 'code_lock' is not defined
I don't know if I should override the run(self) method of bot, but when I tried that it never actually ran the method run and I also receive the same error from all the threads created: that int is not callable (and I can't see where I can possibly be using an int as object).
Additionaly I don't know if I am handling correctly the exit signal from keyboard, as you can see I am trying to deal with that using a terminate variable, but I don't think that this is the problem...
One last thing, the ConnectionError exception is not being appropriately handled, as it's saying "Retrying...", but in fact it will not retry, but I am aware of that and it should be ok, I'll fix it latter.
Worth mentioning that I'm not very used to deal with multi-threading and when I do deal with it, it is in C or C++.
Edit
I can make the code work by using global variables, but I do not want to do that, I prefer to avoid using globals. My attempts of passing the variables directly to the instances of the class bot or by passing an data-object to it weren't successful so far, whenever I pass the variables or the auxiliar object to bot I am unable to access them as attributes using self. and without self. Python claims that the variable was not defined.
Here is the updated code, without success yet:
import requests
import sys
import threading
import signal
import time
class Shared:
def __init__(self, code, url, file, log, code_lock, file_lock, log_lock):
self.code = code
self.url = url
self.file = file
self.log = log
self.code_lock = code_lock
self.file_lock = file_lock
self.log_lock = log_lock
class bot(threading.Thread):
def __init__(self, data):
threading.Thread.__init__(self)
self.terminate = False
self.data = data
#classmethod
def getCode(self):
self.data.code_lock.acquire()
work_code = self.data.code
try:
self.data.code += 1
finally:
self.data.code_lock.release()
return work_code
#classmethod
def checkCode(self, work_code):
try:
#if(code % 1000000 == 0):
print("Code "+str(work_code)+" is being checked...\n")
html = requests.get(self.data.url+str(work_code))
html.encoding = 'utf-8'
return not 'Page Not Found' in html.text
except requests.exceptions.ConnectionError:
print("Connection Error! Retrying...\n")
time.sleep(0.5)
except KeyboardInterrupt:
self.logCode(work_code)
sys.exit()
#classmethod
def storeCode(self, work_code):
self.data.file_lock.acquire()
try:
self.data.file.write(work_code+'\n')
finally:
self.data.file_lock.release()
#classmethod
def logCode(self, work_code):
self.data.log_lock.acquire()
try:
self.data.log.write(work_code+'\n')
finally:
self.data.log_lock.release()
#classmethod
def run(self):
while(not self.terminate):
work_code = self.getCode()
if(self.checkCode(work_code)):
self.storeCode(work_code)
self.logCode(work_code)
def main(code = 0, threads = 16):
#bots = [threading.Thread(target=bot) for bot in range(threads)]
bots = []
url = 'https://www.test.ing/codes/'
file = open("valid-codes.txt", "a")
log = open("log.txt", "a")
code_lock = threading.Lock()
file_lock = threading.Lock()
log_lock = threading.Lock()
data = Shared(code, url, file, log, code_lock, file_lock, log_lock)
def signal_handler(signal, frame):
print('Exiting...\n')
log_lock.acquire()
try:
log.write("\n\n"+str(time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime()))+"\n")
finally:
log_lock.release()
for bot in bots:
bot.terminate = True
for bot in bots:
bot.join()
sys.exit(0)
#for bot in bots:
# bot.start()
for i in range(threads):
t = bot(data)
bots.append(t)
t.start()
signal.signal(signal.SIGINT, signal_handler)
while True:
signal.pause()
main(736479509787350, 4)
Yet, the working code with global variables:
import requests
import sys
import threading
import signal
import time
code = 736479509787350
url = 'https://www.test.ing/codes/'
file = open("valid-codes.txt", "a")
log = open("log.txt", "a")
code_lock = threading.Lock()
file_lock = threading.Lock()
log_lock = threading.Lock()
terminate = False
class bot(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
#classmethod
def getCode(self):
global code
code_lock.acquire()
work_code = code
try:
code += 1
finally:
code_lock.release()
return work_code
#classmethod
def checkCode(self, work_code):
try:
if(code % 1000000 == 0):
print("Code "+str(work_code)+" is being checked...\n")
html = requests.get(url+str(work_code))
html.encoding = 'utf-8'
if(not 'Page Not Found' in html.text):
time.sleep(0.5)
html = requests.get(url+str(work_code)+":999999999")
html.encoding = 'utf-8'
return 'Page Not Found' in html.text
except requests.exceptions.ConnectionError:
#print("Connection Error! Retrying...\n")
time.sleep(1)
return self.checkCode(work_code)
except KeyboardInterrupt:
self.logCode(work_code)
sys.exit()
#classmethod
def storeCode(self, work_code):
global file_lock
global file
file_lock.acquire()
try:
file.write(str(work_code)+'\n')
finally:
file_lock.release()
#classmethod
def logCode(self, work_code):
global log_lock
global log
log_lock.acquire()
try:
log.write(str(work_code)+'\n')
finally:
log_lock.release()
#classmethod
def run(self):
global terminate
while(not terminate):
work_code = self.getCode()
if(self.checkCode(work_code)):
print("Code "+str(work_code)+" is a valid code!\n")
self.storeCode(work_code)
self.logCode(work_code)
def main(threads = 16):
#bots = [threading.Thread(target=bot) for bot in range(threads)]
bots = []
#url = 'https://www.facebook.com/leticia.m.demenezes/posts/'
#file = open("valid-codes.txt", "a")
#log = open("log.txt", "a")
#code_lock = threading.Lock()
#file_lock = threading.Lock()
#log_lock = threading.Lock()
def signal_handler(signal, frame):
global terminate
print('Exiting...\n')
log_lock.acquire()
try:
log.write("\n\n"+str(time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime()))+"\n")
finally:
log_lock.release()
terminate = True
for bot in bots:
bot.join()
sys.exit(0)
#for bot in bots:
# bot.start()
for i in range(threads):
t = bot()
bots.append(t)
t.start()
signal.signal(signal.SIGINT, signal_handler)
while True:
signal.pause()
main()
You could make the code_lock global as you're trying to do, but why not just pass it into each bot class?
t = bot(code_lock)
Next create a constructor for your class:
class bot(threading.Thread):
def __init__(self, code_lock):
threading.Thread.__init__(self)
self.code_lock = code_lock
Now, whenever you try to use code_lock inside your bot class, always prefix it with self (self.code_lock).
If you really insist on using global variables, then look into the global keyword.
It's clear that you are trying to access code_lock out of it's scope, may be you can follow #MartinKonecny suggestion to fix that.
I could see that even after fixing code_lock problem, your code has lot of problems. as soon as you fix code_lock problem you'll face similar issue with the variable code in the same function getCode.
After fixing all those compiled time issues, you'll face issues with your whole class implementation, this is not the way to implement Python classes.
It's better that you go through this to know more about python name spaces and classes.
Edit: I figured it out shortly after posting, it's amazing how asking a question can help you re-examine things :-). I commented the switch in the code.
I'm working on a class to download single frames from motion jpeg streams every so many seconds. It worked fine until I added some code to disconnect from the stream once a single jpeg is loaded. Now the "recorder" seems to be storing the first frame retrieved and not replacing the "image" with new content. I can destroy and recreate the object every time to fix this but that's not a very elegant solution. Any help would be appreciated!
Here's the code for the Recorder class:
import cv2
import urllib2
import threading
from PIL import Image
import numpy as np
class MJpegCam:
def __init__(self, ip, timeout=5):
self.ip = ip
self.bytes= ''
self.image = ''
self.stream = None
self.stopcam = False
self.timeout = timeout
def start(self):
self.stream=urllib2.urlopen(self.ip, timeout=self.timeout)
def run():
while True:
if self.stopcam:
self.stopcam = False
return
try:
self.bytes+=self.stream.read(1024)
a = self.bytes.find('\xff\xd8')
b = self.bytes.find('\xff\xd9')
if a!=-1 and b!=-1:
jpg = self.bytes[a:b+2]
self.bytes= self.bytes[b+2:]
cv2img = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8),cv2.CV_LOAD_IMAGE_COLOR)
try:
cv2RGB = cv2.cvtColor(cv2img,cv2.COLOR_BGR2RGB)
self.image = Image.fromarray(cv2RGB)
self.stop() #This is where the program was breaking
return #
except Exception as e:
pass
except AttributeError as e:
pass
thread = threading.Thread(target=run)
thread.start()
def stop(self):
self.stream.close()
self.stopcam = False #this needed to be switched to False
self.bytes = ''
def getImage(self):
return self.image
In the actual program I'm running multiple objects on separate processes but here's the basic idea:
cam = MJpegCam(ip)
secs = 10
while(i < end):
cam.start()
time.sleep(cam.timeout)
cam.stop()
time.sleep(secs - cam.timeout)
I've been looking into a way to directly change variables in a running module.
What I want to achieve is that a load test is being run and that I can manually adjust the call pace or whatsoever.
Below some code that I just created (not-tested e.d.), just to give you an idea.
class A():
def __init__(self):
self.value = 1
def runForever(self):
while(1):
print self.value
def setValue(self, value):
self.value = value
if __name__ == '__main__':
#Some code to create the A object and directly apply the value from an human's input
a = A()
#Some parallelism or something has to be applied.
a.runForever()
a.setValue(raw_input("New value: "))
Edit #1: Yes, I know that now I will never hit the a.setValue() :-)
Here is a multi-threaded example. This code will work with the python interpreter but not with the Python Shell of IDLE, because the raw_input function is not handled the same way.
from threading import Thread
from time import sleep
class A(Thread):
def __init__(self):
Thread.__init__(self)
self.value = 1
self.stop_flag = False
def run(self):
while not self.stop_flag:
sleep(1)
print(self.value)
def set_value(self, value):
self.value = value
def stop(self):
self.stop_flag = True
if __name__ == '__main__':
a = A()
a.start()
try:
while 1:
r = raw_input()
a.set_value(int(r))
except:
a.stop()
The pseudo code you wrote is quite similar to the way Threading / Multiprocessing works in python. You will want to start a (for example) thread that "runs forever" and then instead of modifying the internal rate value directly, you will probably just send a message through a Queue that gives the new value.
Check out this question.
Here is a demonstration of doing what you asked about. I prefer to use Queues to directly making calls on threads / processes.
import Queue # !!warning. if you use multiprocessing, use multiprocessing.Queue
import threading
import time
def main():
q = Queue.Queue()
tester = Tester(q)
tester.start()
while True:
user_input = raw_input("New period in seconds or (q)uit: ")
if user_input.lower() == 'q':
break
try:
new_speed = float(user_input)
except ValueError:
new_speed = None # ignore junk
if new_speed is not None:
q.put(new_speed)
q.put(Tester.STOP_TOKEN)
class Tester(threading.Thread):
STOP_TOKEN = '<<stop>>'
def __init__(self, q):
threading.Thread.__init__(self)
self.q = q
self.speed = 1
def run(self):
while True:
# get from the queue
try:
item = self.q.get(block=False) # don't hang
except Queue.Empty:
item = None # do nothing
if item:
# stop when requested
if item == self.STOP_TOKEN:
break # stop this thread loop
# otherwise check for a new speed
try:
self.speed = float(item)
except ValueError:
pass # whatever you like with unknown input
# do your thing
self.main_code()
def main_code(self):
time.sleep(self.speed) # or whatever you want to do
if __name__ == '__main__':
main()