I am developing a plugin for the GIS software, QGIS. I have a QAction icon which, when checked, connects layers in a group to a function whenever their visibility is toggled. Then when it is unchecked, it is supposed to disconnect these functions but instead I receive an error:
Traceback (most recent call last):
File "C:/Users/Me/.qgis2/python/plugins\Example\Example.py", line 248, in run
layers.visibilityChanged.disconnect(print_one)
TypeError: 'function' object is not connected
This is an example code:
def run(self, checked):
root = QgsProject.instance().layerTreeRoot()
group = root.findGroup('Group')
def print_one():
print 'one'
if checked == True:
for layers in group.children():
layers.visibilityChanged.connect(print_one)
else:
for layers in group.children():
layers.visibilityChanged.disconnect(print_one)
Why is the signal not being disconnected?
I could just use layers.visibilityChanged.disconnect() but this disconnects all signals to it so is not in my interest.
For what I understood in PyQt manual, you should try this way :
layers.disconnect(print_one)
But I'm not sure and sadly I don't have time to try it...
From the documentation (emphasis mine):
disconnect([slot])
Disconnect one or more slots from a signal. An exception will be raised if the slot is not connected to the signal or if the signal has no connections at all.
Thus, you are receiving an exception because the signal is not connected to the slot when you are trying to disconnect it.
As a workaround:
if checked == True:
for layers in group.children():
layers.visibilityChanged.connect(print_one)
else:
for layers in group.children():
try:
layers.visibilityChanged.disconnect(print_one)
except:
pass
Guess I found an alternative method which is to include an if statement to check if the QAction icon is checked or not and place this inside the print_one() function:
def run(self):
root = QgsProject.instance().layerTreeRoot()
group = root.findGroup('Group')
def print_one():
if self.plugin_icon.isChecked():
print 'one'
else:
layers.visibilityChanged.disconnect(print_one)
for layers in group.children():
layers.visibilityChanged.connect(print_one)
Still curious as to why I couldn't disconnect it using the method shown in the question but in the meantime, this works.
Related
I'm trying to create a networking project using UDP connections. The server that I'm creating has to multithread in order to be able to receive multiple commands from multiple clients. However when trying to multithread the server, only one thread is running. Here is the code:
def action_assigner():
print('Hello Assign')
while True:
if work_queue.qsize() != 0:
data, client_address, request_number = work_queue.get()
do_actions(data, client_address, request_number)
def task_putter():
request_number = 0
print('Hello Task')
while True:
data_received = server_socket.recvfrom(1024)
request_number += 1
taskRunner(data_received, request_number)
try:
thread_task = threading.Thread(target=task_putter())
action_thread = threading.Thread(target=action_assigner())
action_thread.start()
thread_task.start()
action_thread.join()
thread_task.join()
except Exception as e:
server_socket.close()
When running the code, I only get Hello Task as the result meaning that the action_thread never started. Can someone explain how to fix this?
The problem here is that you are calling the functions that should be the "body" of each thread when creating the Threads themselves.
Upon executing the line thread_task = threading.Thread(target=task_putter()) Python will resolve first the expession inside the parentheses - it calls the function task_putter, which never returns. None of the subsequent lines on your program is ever run.
What we do when creating threads, and other calls that takes callable objects as arguments, is to pass the function itself, not calling it (which will run the function and evaluate to its return value).
Just change both lines creating the threads to not put the calling parentheses on the target= argument and you will get past this point:
...
try:
thread_task = threading.Thread(target=task_putter)
action_thread = threading.Thread(target=action_assigner)
...
I'm new at NAO programming and I'm having some trouble regarding the ALAudioDevice API.
My problem is the following one: I wrote a python module that should record raw data from the front microphone.
The documentation of the ALAudioDevice API says that the method "subscribe(...)" calls the function "process" automatically
and regularly with raw data from microphones as inputs. I wrote a code to execute this process (see bellow), and it runs without raising
the error flag. However, the subscribe is bypassing the function "process" and the module doesn't get any audio at all.
Has someone had the same problem?
import qi
class AudioModule(object):
def __init__(self):
super(AudioModule, self).__init__()
self.moduleName = "AudioModule"
try :
self.ALAudioDevice = ALProxy("ALAudioDevice")
except Exception, e:
self.logger.error("Error when creating proxy on ALAudioDevice:")
self.logger.error(e)
def begin_stream(self):
self.ALAudioDevice.setClientPreferences(self.moduleName, 16000, 3, 0)
self.ALAudioDevice.subscribe(self.moduleName)
def end_stream(self):
self.ALAudioDevice.unsubscribe(self.moduleName)
def processRemote( self, nbOfChannels, samplesByChannel, altimestamp, buffer ):
nbOfChannels = nbOfChannels
mylogger = qi.Logger("data")
mylogger.info("It works !" + str(nbOfChannels))
class MyClass(GeneratedClass):
def __init__(self):
GeneratedClass.__init__(self, False)
self.audio = AudioModule()
def onLoad(self):
self.serviceId = self.session().registerService("AudioModule", self.audio)
pass
def onUnload(self):
if self.serviceId != -1:
self.session().unregisterService(self.serviceId)
self.serviceId = -1
pass
def onInput_onStart(self):
self.audio.begin_stream()
self.onInput_onStop()
pass
def onInput_onStop(self):
self.audio.end_stream()
self.onUnload
self.onStopped()
pass
It appears you are subscribing to the audio from a Choregraphe box. I'm not sure it is supposed to work.
But in this configuration the Python code is executed from within the same process as the ALAudioDevice service. So probably you should name your callback "process" instead of "processRemote".
Otherwise, you can still do this from a separate Python script.
Community!
I have a little Problem with the Python-DBus-API. I create a signal-receiver and it does its job. However if I try to remove the signal, it won't be removed and the signalhandler (sigHandler) is happily called every time the signal matches.
class A(threading.Thread)
bus = None
mainloop = None
systemBusMainLoop = None
signalReceiver = None
def __init__(self,dbusMainLoop):
log("Hello.")
super(A, self).__init__()
gobject.threads_init()
self.mainloop = gobject.MainLoop()
self.systemBusMainLoop = dbusMainLoop
self.bus = dbus.SystemBus(mainloop=dbusMainLoop)
self.signalReceiver = self.bus.add_signal_receiver(self.sigHandler,
bus_name="org.bluez",
dbus_interface="org.freedesktop.DBus.Properties",
signal_name="PropertiesChanged",
path_keyword="path")
def run(self):
self.mainloop.run()
log("Running.")
def end(self):
log("Shutting down...")
self.bus.remove_signal_receiver(self.sigHandler,
self.signalReceiver,
dbus_interface="org.freedesktop.DBus.Properties")
#self.signalReceiver.remove() #tried this also
if (self.mainloop):
self.mainloop.quit()
del self.signalReceiver
log("Bye.")
def sigHandler(self, interface, changed, invalidated, path)
print interface
print changed
print invalidated
print path
Called:
dbusA = A(dbusMainLoop=dbus.mainloop.glib.DBusGMainLoop())
dbusA.run()
#doing something unrelated
dbusA.end() #remove the Signal
del dbusA
Do i miss something? Why ist my sigHandler not removed (or why is my match not removed).
Thanks in advance!
The line you commented out (self.signalReceiver.remove()) works.
add_signal_receiver() returns a SignalMatch instance on which you can call remove() method to unregister your callback.
The problem in your code snippet is that dbusA.run() is a blocking call because it calls self.mainloop.run() which itself is a blocking call.
This said, program execution will never reach dbusA.end(), thus signal unregistering and quitting the run loop will not happen. You can however call this method from a different thread, or from any event handler of your dbus connection.
Depending on a conditions I would like to connect/re-connect a button to a different function.
Let's say I have a button:
myButton = QtGui.QPushButton()
For this example let's say I check if there is an internet connection.
if connected == True:
myButton.clicked.connect(function_A)
elif connected == False:
myButton.clicked.connect(function_B)
First of all I would like to disconnect a button from any function it was already connected before the button is being re-assigned/re-connected to another function (function_A or function_B).
Secondly, I have already noticed that after the button is re-connected it takes an extra click for the button to pick up a new function. After the button is re-connected to another function it still attempts to run a previous function - a function to which a button was connected earlier (before a re-connection). Please advice. Thanks in advance!
EDITED LATER:
It appears a widget's .disconnect() method can be used to disconnect a button from a function it it is connected.
myButton.disconnect()
Unfortunately .disconnect() throws an error if a widget is not connected to any function.
To get around it I am using Try/Except. But I would rather use a more elegant solution...
try: myButton.clicked.disconnect()
except Exception: pass
If you need to reconnect signals in many places, then you could define a generic utility function like this:
def reconnect(signal, newhandler=None, oldhandler=None):
try:
if oldhandler is not None:
while True:
signal.disconnect(oldhandler)
else:
signal.disconnect()
except TypeError:
pass
if newhandler is not None:
signal.connect(newhandler)
...
if connected:
reconnect(myButton.clicked, function_A)
else:
reconnect(myButton.clicked, function_B)
(NB: the loop is needed for safely disconnecting a specific handler, because it may have been connected multple times, and disconnect(slot) only removes one connection at a time.).
Try this:
from PyQt4 import QtGui as gui
app = gui.QApplication([])
myButton = gui.QPushButton()
def function_A():
myButton.clicked.disconnect() #this disconnect all!
myButton.clicked.connect(function_B)
print 'function_A'
def function_B():
myButton.clicked.disconnect(function_B) #this disconnect function_B
myButton.clicked.connect(function_A)
print 'function_B'
myButton.clicked.connect(function_A)
myButton.setText("Click me!")
myButton.show()
app.exec_()
Concise way for 3.4+ with contextlib.suppress:
with contextlib.suppress(RuntimeError):
button.clicked.disconnect()
button.connect(func_a if condition else func_b)
I'm currently using PySpeech to recognize speech. I'm trying to get voice recognition to start without Windows Speech Recognition's default commands.
From googling, I've found that changing this line in speech.py from:
_recognizer = win32com.client.Dispatch("SAPI.SpSharedRecognizer")
to:
_recognizer = win32com.client.Dispatch("SAPI.SpInprocRecognizer")
doesn't include all the default commands. When I test whether or not the recognizer is listening, it returns false. At this point I'm just trying to get pySpeech to recognize what I'm saying and say it back to me.
Test Code:
import speech
speech.say("say something") #<--- says "say something"
print speech.input() #<--- gets stuck here
print speech.islistening() #<----- prints False
speech.py:
"""
speech recognition and voice synthesis module.
Please let me know if you like or use this module -- it would make my day!
speech.py: Copyright 2008 Michael Gundlach (gundlach at gmail)
License: Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
For this module to work, you'll need pywin32 (http://tinyurl.com/5ezco9
for Python 2.5 or http://tinyurl.com/5uzpox for Python 2.4) and
the Microsoft Speech kit (http://tinyurl.com/zflb).
Classes:
Listener: represents a command to execute when phrases are heard.
Functions:
say(phrase): Say the given phrase out loud.
input(prompt, phraselist): Block until input heard, then return text.
stoplistening(): Like calling stoplistening() on all Listeners.
islistening(): True if any Listener is listening.
listenforanything(callback): Run a callback when any text is heard.
listenfor(phraselist, callback): Run a callback when certain text is heard.
Very simple usage example:
import speech
speech.say("Say something.")
print "You said " + speech.input()
def L1callback(phrase, listener):
print phrase
def L2callback(phrase, listener):
if phrase == "wow":
listener.stoplistening()
speech.say(phrase)
# callbacks are executed on a separate events thread.
L1 = speech.listenfor(["hello", "good bye"], L1callback)
L2 = speech.listenforanything(L2callback)
assert speech.islistening()
assert L2.islistening()
L1.stoplistening()
assert not L1.islistening()
speech.stoplistening()
"""
from win32com.client import constants as _constants
import win32com.client
import pythoncom
import time
import thread
# Make sure that we've got our COM wrappers generated.
from win32com.client import gencache
gencache.EnsureModule('{C866CA3A-32F7-11D2-9602-00C04F8EE628}', 0, 5, 0)
_voice = win32com.client.Dispatch("SAPI.SpVoice")
_recognizer = win32com.client.Dispatch("SAPI.SpInprocRecognizer")
_listeners = []
_handlerqueue = []
_eventthread=None
class Listener(object):
"""Listens for speech and calls a callback on a separate thread."""
_all = set()
def __init__(self, context, grammar, callback):
"""
This should never be called directly; use speech.listenfor()
and speech.listenforanything() to create Listener objects.
"""
self._grammar = grammar
Listener._all.add(self)
# Tell event thread to create an event handler to call our callback
# upon hearing speech events
_handlerqueue.append((context, self, callback))
_ensure_event_thread()
def islistening(self):
"""True if this Listener is listening for speech."""
return self in Listener._all
def stoplistening(self):
"""Stop listening for speech. Returns True if we were listening."""
try:
Listener._all.remove(self)
except KeyError:
return False
# This removes all refs to _grammar so the event handler can die
self._grammar = None
if not Listener._all:
global _eventthread
_eventthread = None # Stop the eventthread if it exists
return True
_ListenerBase = win32com.client.getevents("SAPI.SpSharedRecoContext")
class _ListenerCallback(_ListenerBase):
"""Created to fire events upon speech recognition. Instances of this
class automatically die when their listener loses a reference to
its grammar. TODO: we may need to call self.close() to release the
COM object, and we should probably make goaway() a method of self
instead of letting people do it for us.
"""
def __init__(self, oobj, listener, callback):
_ListenerBase.__init__(self, oobj)
self._listener = listener
self._callback = callback
def OnRecognition(self, _1, _2, _3, Result):
# When our listener stops listening, it's supposed to kill this
# object. But COM can be funky, and we may have to call close()
# before the object will die.
if self._listener and not self._listener.islistening():
self.close()
self._listener = None
if self._callback and self._listener:
newResult = win32com.client.Dispatch(Result)
phrase = newResult.PhraseInfo.GetText()
self._callback(phrase, self._listener)
def say(phrase):
"""Say the given phrase out loud."""
_voice.Speak(phrase)
def input(prompt=None, phraselist=None):
"""
Print the prompt if it is not None, then listen for a string in phraselist
(or anything, if phraselist is None.) Returns the string response that is
heard. Note that this will block the thread until a response is heard or
Ctrl-C is pressed.
"""
def response(phrase, listener):
if not hasattr(listener, '_phrase'):
listener._phrase = phrase # so outside caller can find it
listener.stoplistening()
if prompt:
print prompt
if phraselist:
listener = listenfor(phraselist, response)
else:
listener = listenforanything(response)
while listener.islistening():
time.sleep(.1)
return listener._phrase # hacky way to pass back a response...
def stoplistening():
"""
Cause all Listeners to stop listening. Returns True if at least one
Listener was listening.
"""
listeners = set(Listener._all) # clone so stoplistening can pop()
returns = [l.stoplistening() for l in listeners]
return any(returns) # was at least one listening?
def islistening():
"""True if any Listeners are listening."""
return not not Listener._all
def listenforanything(callback):
"""
When anything resembling English is heard, callback(spoken_text, listener)
is executed. Returns a Listener object.
The first argument to callback will be the string of text heard.
The second argument will be the same listener object returned by
listenforanything().
Execution takes place on a single thread shared by all listener callbacks.
"""
return _startlistening(None, callback)
def listenfor(phraselist, callback):
"""
If any of the phrases in the given list are heard,
callback(spoken_text, listener) is executed. Returns a Listener object.
The first argument to callback will be the string of text heard.
The second argument will be the same listener object returned by
listenfor().
Execution takes place on a single thread shared by all listener callbacks.
"""
return _startlistening(phraselist, callback)
def _startlistening(phraselist, callback):
"""
Starts listening in Command-and-Control mode if phraselist is
not None, or dictation mode if phraselist is None. When a phrase is
heard, callback(phrase_text, listener) is executed. Returns a
Listener object.
The first argument to callback will be the string of text heard.
The second argument will be the same listener object returned by
listenfor().
Execution takes place on a single thread shared by all listener callbacks.
"""
# Make a command-and-control grammar
context = _recognizer.CreateRecoContext()
grammar = context.CreateGrammar()
if phraselist:
grammar.DictationSetState(0)
# dunno why we pass the constants that we do here
rule = grammar.Rules.Add("rule",
_constants.SRATopLevel + _constants.SRADynamic, 0)
rule.Clear()
for phrase in phraselist:
rule.InitialState.AddWordTransition(None, phrase)
# not sure if this is needed - was here before but dupe is below
grammar.Rules.Commit()
# Commit the changes to the grammar
grammar.CmdSetRuleState("rule", 1) # active
grammar.Rules.Commit()
else:
grammar.DictationSetState(1)
return Listener(context, grammar, callback)
def _ensure_event_thread():
"""
Make sure the eventthread is running, which checks the handlerqueue
for new eventhandlers to create, and runs the message pump.
"""
global _eventthread
if not _eventthread:
def loop():
while _eventthread:
pythoncom.PumpWaitingMessages()
if _handlerqueue:
(context,listener,callback) = _handlerqueue.pop()
# Just creating a _ListenerCallback object makes events
# fire till listener loses reference to its grammar object
_ListenerCallback(context, listener, callback)
time.sleep(.5)
_eventthread = 1 # so loop doesn't terminate immediately
_eventthread = thread.start_new_thread(loop, ())
Well, as I mentioned, in-process recognizers don't have default input sources or recognition engines set up. In order to get the in-process recognizer to listen, you need to set these via _recognizer.SetInput (to set the input source) and _recognizer.SetRecognizer (to set the recognition engine)
The challenge for you is to get the default input source and recognition engine, respectively. If you were using C++, this would be straightforward; there's a helper function in sphelper.h that gets the default input source: SpGetDefaultTokenFromCategoryId(SPCAT_AUDIOIN, &cpToken), and I published a function on my blog that gets the default recognition engine.
But I don't know how to translate those functions into Python; perhaps you do.
I found the following post when I faced the same problem.
Basically, you have to modify some lines on speech.py:
Change the line _recognizer = win32com.client.Dispatch("SAPI.SpSharedRecognizer") into _recognizer = win32com.client.Dispatch("SAPI.SpInProcRecognizer")
Add this line after the previous line: _recognizer.AudioInputStream = win32com.client.Dispatch("SAPI.SpMMAudioIn")
Change the line _ListenerBase = win32com.client.getevents("SAPI.SpSharedRecoContext") into _ListenerBase = win32com.client.getevents("SAPI.SpInProcRecoContext")
This question is really old but here's a module based on PySpeech (Python 2) that supports both InProcRecognizers and SharedRecognizer: winspeech. Works for both Python 2 and 3.