PySide/PyQt signal that can transmit any value (including None) - python

I have a problem using Qt signal/slot mechanism in PySide when I want to send None.
Suppose I have a class named Calculator (a subclass of QObject) that can perform certain calculations the result of which can be anything, i.e. any type of Python object or even None. I need the instances of Calculator class to be able to signal the result to some consumer objects (subclasses of QObject).
What I had:
class Calculator(QObject):
finished = PySide.QtCore.Signal(object) # object means it can transmit anything
def calc(self):
... # calculation of the result
self.finished.emit(result)
class Consumer(QObject):
def __init__(self, calculator):
...
calculator.finished.connect(self.consume)
def consume(self, result): # do something with the result
...
This works fine except the situation when result is None. Then the program crashes when emitting the signal. It seems as if None is not a Python object (which may be true, I am not that proficient in the language standards).
Now I have a workaround, using two signals:
finished = PySide.QtCore.Signal((),(object,))
and:
def calc(self):
... # calculation of the result
if result is None:
self.finished.emit()
else:
self.finished[object].emit(result)
This solution works but it is complicated because it requires the consumer objects to link the signal twice. Either to two slots or to one slot with one default argument equal to None.
class Consumer(QObject):
def __init__(self, calculator):
...
calculator.finished.connect(self.consume)
calculator.finished[object].connect(self.consume)
def consume(self, result=None): # do something with the result
...
This is complicated and prone to errors when creating many different consumer classes.
I think this problem is the same with PyQt, with the difference that alternative signals are defined using lists [], [object] rather than tuples (),(object,).
My question is: is there any simple solution to this problem? Ideally with just one signal?

As an aside, this bug still exists in PySide where it segfaults on the transmission of a None signal as of version 1.2.1 (has existed since 1.1.0). There is a bug report at:
https://bugreports.qt-project.org/browse/PYSIDE-17
Obviously V.K.'s solution of encapsulating the None within a separate class still works, as does choosing another type to transmit instead (I switched my None to float('nan')). I just wanted to update this as I ran into the same issue and found this, and later the bug report explaining the segfault.

Just after posting my problem I found an answer. So I appologize for answering my own question - I know it is not how it should be on StackOverflow. I created a class named ResultHolder which encapsulates the real result (result is a member variable of this class). Then I am transmitting instances of this ResultHolder class. The rest of the solution is then just straightforward.

Related

How to check if method exist from within a Python object

Context and intentions: I want to use an object m_o of type My_object as a way of interfacing with another object called s_o of type Stubborn_object. For the sake of easy understanding, they should behave like if My_object inherited from Stubborn_object, in the way that calling an attribute that doesn't exist in My_object should call the attribute in Stubborn_object.
However, the tricky thing is that I wouldn't be asking this question if I could simply inherit My_object from Stubborn_object. It appears that I can't inherit from it, and, for many reasons, I also can't modify the code of the Stubborn_object class, so I have to use it as it is. Please note that trying to inherit isn't the issue of the question here. I know that other solutions exist for my practical problem, but I really want answers to stay on topic for many reasons. I suspect that other users can have different problems than mine and still be unable to inherit a class. Furthermore, not being able to inherit a class is not the only reason that could make someone read this question. In fact, it's quite a general Python object-oriented problem. I also believe the solution of my problem could be useful in other applications, like custom error handling within the object itself when an attribute is not found, or in thread management to lock the instance as soon as an attribute is called.
In addition to the problem of inheritance, let's suppose that I can't use conditions at higher levels to handle these cases, so everything has to be done inside My_object instance or its parents. That means that I can't use hasattr(m_o, attribute_name) to determine if I should call getattr(m_o, attribute_name) or getattr(s_o, attribute_name). This also means that any try/except blocks and other preconditions must be inside the My_object class or its parents. The point of this question is not about detecting exceptions when calling an attribute from outside the My_object instance. A try/catch block normally has to be outside the My_object class, and I previously stated that this can't be allowed.
For the sake of clarity and to provide a complete verifiable example, here is a sample code of the Stubborn_object class. I know that I said I can't inherit from Stubborn_object and the following code includes an inheritable class. Providing an example of an non-inheritable object would only bring confusion and it would'nt be really helpful to the question anyway, so here is a simple example of an inheritable object. The objective of this is to make an easy to understand question, so please just consider that you can't inherit from it:
class Stubborn_object:
def do_something(self):
print("do_something")
def action_to_override():
print("action_to_override")
def action_a(self):
print("action_a")
def action_b(self):
print("action_b")
Objective: Put it simply, I want my class My_object to detect all by itself that a lacking attribute has been called and run some instructions instead of throwing an AttributeError.
Current attempts: Right now, I manually redirect method calls to the Stubborn_object instance like so (it's successful, but not reliable nor scalable because of the use of hardcoding):
class My_object():
def __init__(self, s_o):
self.stubborn_object = s_o
def action_to_override(self):
# Do stuff. This method "overrides" the Stubborn_object.action_to_override method.
print("Here is stuff getting done instead of action_to_override")
def action_a(self):
return self.stubborn_object.action_a()
def action_b(self):
return self.stubborn_object.action_b()
s_o = Stubborn_object()
m_o = My_object(s_o)
m_o.action_to_override() # Executes Stubborn_object.do_something()
m_o.action_a() # Executes Stubborn_object.action_a()
m_o.action_b() # Executes Stubborn_object.action_b()
Executing this code along with the provided Stubborn_object code sample should print:
Here is stuff getting done instead of action_to_override
action_a
action_b
As you can see from methods action_a and action_b, I have to manually call the Stubborn_object methods from whithin the methods in My_object to mimic the attributes of Stubborn_object. This is ineficient, lacks of robustness and will throw an AttributeError exception if we attempt to make an action that wasn't included in the My_object code.
What if I wanted to automatically send method and attribute calls to the Stubborn_object instance without having to rewrite all of its method and attributes in My_object? I believe this can be achieved with detecting if a lacking attribute of My_object instance is called.
Expectations (or sort of): I am open to any solution that allows the My_object class or its parents to determine if the attribute is lacking or not, all within itself. So I believe I am ready to hear extremely original ideas, so go ahead.
On my part, I believe that something that uses parts of this code is the way to go, but it still lacks the "catch any called attribute" part:
class My_object():
def __init__(self, s_o):
# __init__ stays as it was.
self.stubborn_object = s_o
def action_to_override(self):
# This method also stays as it was.
# Do stuff. This method "overrides" the stubborn_object.action_to_override method.
print("Here is stuff getting done instead of action_to_override")
def run_me_when_method_is_not_found(self, method_name, **kwargs):
print("Method " + method_name + " not in 'My_object' class.")
return getattr(self.stubborn_object, method_name)(**kwargs)
So running those lines with the previous code sample
s_o = Stubborn_object()
m_o = My_object(s_o)
m_o.action_to_override() # Executes Stubborn_object.do_something()
m_o.action_a() # Executes Stubborn_object.action_a()
m_o.action_b() # Executes Stubborn_object.action_b()
will print
Here is stuff getting done instead of action_to_override
Method action_a not in 'My_object' class.
action_a
Method action_b not in 'My_object' class.
action_b
Some similar methods will have to be made for getters and setters, however, the idea stays the same. The thing is that this code lacks the ability to detect that an attribute is missing.
Question: How can I run the run_me_when_method_is_not_found when the method is not found in My_object? Especially, how can a My_object instance detect that the method doesn't exists in its class instead of throwing an AttributeError exception?
Thanks a lot.
Seems like overriding __getattribute__ will do exactly what you want: search for attribute in self.stubborn_object if it is missing in self. Put it into My_object class definition:
def __getattribute__(self, attr):
try:
return object.__getattribute__(self, attr)
except AttributeError:
return object.__getattribute__(self.stubborn_object, attr)

Is it possible to instantiate multiple instances of a class through a single classmethod call?

So I've used python as a functional language for a while but I'm trying to do thing "right" and use classes now... and falling down. I'm trying to write a classmethod that can instantiate multiple members of the class (use case is load rows from SQLAlchemy.) I'd like to just be able to call the classmethod and have it return a status code (success/failure) rather than returning a list of objects. Then to access the objects I'll iterate through the class. Here's my code so far (which fails to iterate when I use the classmethod, works fine when I use the normal constructor.) Am I way off-base/crazy here? What's the "pythonic" way to do this? Any help is appreciated and thank you.
class KeepRefs(object):
__refs__ = defaultdict(list)
def __init__(self):
self.__refs__[self.__class__].append(weakref.ref(self))
#classmethod
def get_instances(cls):
for inst_ref in cls.__refs__[cls]:
inst = inst_ref()
if inst is not None:
yield inst
class Credentials(KeepRefs):
def __init__(self,name, username, password):
super(Credentials, self).__init__()
self.name=name
self.username=username
self.password=password
#classmethod
def loadcreds(cls):
Credentials('customer1','bob','password')
return True
success = Credentials.loadcreds()
for i in Credentials.get_instances():
print (i.name)
In your own words - yes, you are off-base and crazy :)
Status-Codes are a thing of C, not languages with proper exception semantics as Python. Modifying global state is a sure recipe for disaster. So - don't do it. Return a list of objects. Throw an exception if something disastrous happens, and just return an empty list if there happen to be no objects. This allows the client code to just do
for item in Thingies.load_thingies():
... # this won't do anything if load_thingies gave us an empty list
without having to painstakingly check something before using it.
Functional languages have certain advantages, and you are going too far the other way in your exploration of the procedural style. Global variables and class variable have their place, but what will happen if you need to fire off two SQAlchemy queries and consume the results in parallels? The second query will stomp over the class attributes that the first one still needs, is what. Using an object attribute (instance attribute) solves the problem, since each result contains its own handle.
If your concern is to avoid pre-fetching the array of results, you are in luck because Python offers the perfect solution: Generators, which are basically lazy functions. They are so nicely integrated in Python, I bet you didn't know you've been using them with every for-loop you write.

PyQt obtaining collection of all registered fields in QWizard

I am working on a simple QWizard that displays some radio buttons on its pages. The buttons on a given page are all part of the same QButtonGroup. The page is registered as a custom field in itself, based on the selection in the button group:
class Page1(QWizardPage):
selectionChanged = pyqtSignal('QString')
def __init__(self, name):
self.group = QButtonGroup()
self.group.addButton(QRadioButton("a"))
self.group.addButton(QRadioButton("b"))
self.group.addButton(QRadioButton("c"))
self.registerField(name, self, 'selection', self.selectionChanged)
#pyqtProperty('QString')
def selection(self):
checkedButton = self.group.checkedButton()
return checkedButton.text() if checkedButton else None
def nextId(self): return -1
I end up registering self as the widget containing the field property simply because QButtonGroup is not a QWidget. All of the other pages look pretty much exactly like this (I am actually using base class to do all the common work, and this is just a minimal example).
I would like to be able to get a list of all the registered fields in the QWizard. I have not found any methods provided by Qt to allow me to do this so I made a workaround by overriding the behavior of each page's registerField method as well as the wizard's addPage:
def registerField(self, name, *args, **kwargs):
self.field_names.add(name)
if self.wizard() is not None:
self.wizard().field_names.add(name)
super().registerField(name, *args, **kwargs)
def addPage(self, page, *args, **kwargs):
self.field_names.union(page.field_names)
return super().addPage(page, *args, **kwargs)
I can then use the field_set attribute of the parent QWizard combined with QWizard.field to access all the values. This seems a bit redundant and therefore unnecessary. Is there a method in Qt to access the complete collection of fields? The relevant section in the documentation does not mention anything, but there are a lot of other details it omits, so that's not very telling.
My assumption is that the functionality, if it exists, would be the same for PyQt4 as for PyQt5. If it is not, I would prefer an answer for PyQt5 since that is what I am using at the moment.
You said that if the answer is negative it would have to be "pretty convincing." You admit that the documentation contains no mention of the function you want, and I will point out that no such function appears in the list of public functions for QWizard. Therefore the desired function, if it exists at all, is undocumented. To me, that consideration alone would be a "pretty convincing" reason not to use it. The next release of Qt might not have that function, or it might not work the same way.
Meanwhile you have an acceptable solution with eight lines of straightforward python code. Given the choice between that and calling an undocumented function (if you can find it), the python solution is vastly superior in all practical respects.
There is a potential problem with your Python code, however. You override the function QWizard.addPage, but there is another function QWizard.removePage that should probably be overridden as well. An alternative approach, which I would prefer, is not to store the field_names in QWizard at all but only in the individual pages. Add a method to QWizard to dynamically build a set of all the current field_names:
def all_field_names(self):
return {s for page_id in self.pageIds() for s in self.page(page_id).field_names}
[I didn't have a good way of testing this function, but I think you get the idea.] Now you remove the overridden method QWizard.addPage, remove the variable field_names from QWizard, and remove the middle two lines of register_field. Now you have only five lines of Python code, which will work regardless of how pages are added or removed. And you no longer store the field names in two places.
For what it's worth, whenever I'm confronted with a choice between using Qt's functionality or basic Python functionality, I always lean toward Python. I use threads instead of QThreads, threading locks and timers instead of Qt equivalents, Python method objects and callbacks instead of custom Slots and Signals. Qt was written for C++ programmers and that often means that it's not as "pythonic" as I would like.

How can I find out why/when a Python object loses attributes?

Update 2013-02-08
I have an idea now why I haven't been able to reproduce this problem in a small piece of test code. In a small program, Python's garbage collector isn't very active. I believe the problem is that Python is collecting some objects that are only referenced in GObject. I think it's a regression involving this bug, or a new similar bug.
I figured this out because I encountered the same problem again, but with my own class (which has references only from GObject objects) -- this time the entire dict is getting wiped out on the object. Uf I use the code here to monitor one of the attributes that dissappears, it doesn't disappear! It seems the extra reference keeps the attributes around. That smells like a garbage collector problem. I confirmed this by having the object add itself to a global list during initialization... that also fixes the problem as it occurs now.
Original Problem
I am experiencing some bizarre behavior with a PyGTK GUI. I have an object which is consistently losing a large number of attributes. I am trying to determine if this is a bug in my code, the Python interpreter, or PyGTK.
I make no calls to delattr(). I have tried detecting if anything is calling the __delattr__() method of my object by overriding __delattr__() with code that always raises an exception. I am able to reproduce the event which causes the object to lose its attributes but the exception is never raised. I'm not sure of another way to find out what function calls (if any) are causing the object to lose attributes.
The object in question is working perfectly at all times up until it suddenly loses attributes I'm trying to access.
The attribute loss occurs consistently after performing some actions in the GUI that have nothing to do with the object that is losing attributes. I discovered it by accident; there may be other actions that cause the object to lose its attributes.
I have added print id(self) to the method which access the disappearing attribute. The id that is printed is the same before and after the attribute disappears.
Any suggestions on how to track down the source of this problem?
Reference code below: (Note: I will update this code if/when I come up with a simplified test case that reproduces the problem. Right now the total code required to reproduce the bug is too big to post here.)
Here is the class for my object which loses its attributes. This is obviously a minimized version of the real functional code, but I am using this for debugging and the problem still occurs.
It is a subclass of my custom MenuBar class.
Note that the on_file_import__activate() method is connected to the signal for the menu item by one of the parent classes.
class FluidClassManagerWindowMenu(MenuBar):
menu_items = [("File",("Import",))]
def __init__(self, parent):
# XXX: different name than self.parent to see if it stops disappearing
self._xxx_my_parent = parent
MenuBar.__init__(self, parent)
def __delattr__(self,attr):
# XXX: trying to find the cause for lost attributes
traceback.print_stack()
def on_file_import__activate(self, widget=None, data=None):
# XXX: this is the same before and after the attributes disappear
print id(self)
# XXX: print the list of attributes to see what disappears
print dir(self)
# XXX: this works until the _xxx_my_parent attribute disappears
print self._xxx_my_parent
If you're curious, here is the complete source for my MenuBar class. It is a pygtkhelpers SlaveView, which inherits from GObject. The pygtkhelpers delegate does the automagic signal connection to the on_file_import__activate method above.
class MenuBar(pygtkhelpers.delegates.SlaveView):
def __init__(self, parent):
SlaveView.__init__(self)
self.parent = parent
def create_ui(self):
menu_bar = gtk.MenuBar()
menu_bar.set_pack_direction(gtk.PACK_DIRECTION_LTR)
for menu_name, items in self.menu_items:
menu = gtk.Menu()
submenu = gtk.MenuItem(menu_name)
submenu.set_submenu(menu)
for item_name in items:
if not item_name:
menu.append(gtk.MenuItem())
continue
menuitem = gtk.MenuItem(item_name)
fixed_item_name = item_name.lower().replace(' ','_')
fixed_menu_name = menu_name.lower().replace(' ','_')
attr_name = '%s_%s' % (fixed_menu_name,fixed_item_name)
# set an attribute like self.edit_vial_layout
# so pygtkhelpers can find the widget to connect the signal from
setattr(self,attr_name,menuitem)
menu.append(menuitem)
menu_bar.append(submenu)
self.vbox = gtk.VBox()
self.vbox.pack_start(menu_bar)
self.vbox.show_all()
self.widget.add(self.vbox)
List of attributes which disappear from the object:
'_model', '_props', '_toplevel', '_xxx_my_parent', 'file_import', 'parent', 'slaves', 'testtesttest', 'vbox', 'widget'
The attribute parent is what originally was disappearing; I tried assigning its value to _xxx_my_parent in
ManagerWindowMenu.__init__() but it disappears as well. I also added a new attribute in MenuBar.__init__ that I never access, called testtesttest, and it disappears too.
Keep in mind that objects in PyGTK often inherit from GObject. There is likely activity occuring within the GObject framework that is causing you to lose the attributes.
I had a very similar problem. I had a class (SearchWorker) that built a widget for adding to the GUI at runtime. In that widget, there was a button whose "clicked" signal was connected to one of the SearchWorker functions. Whenever the "clicked" signal was fired, many of the attributes of the SearchWorker self object were gone.
I was creating the SearchWorker object in another handler of a different class like this:
worker = SearchWorker()
I presume that once that handler exited something odd happened to the object behind the worker reference. Changing the creation of SearchWorker to:
self.worker = SearchWorker()
solved my problem.
How strange. BTW, using delattr and __delattr__ call is not very common, so I suspect if you are not dealing with two different objects by themselves, getting one while expecting another. Also it may not be a problem with the interpreter, it would crash at much lower level if there was a problem.

What is the correct method of handling events in PyQt 4?

I have seen examples like this:
self.connect(self.ui.add_button, QtCore.SIGNAL('clicked()'),self.printer)
And examples like this:
self.ui.add_button.clicked.connect(self.printer)
I'm just starting to learn Qt; which one should I focus on?
I think that the second example is only supported by some Qt versions (the newer ones), while the first it supported by older ones.
But, both are correct.
AFAIK, the newer style doesn't work if there are overloaded signals, so
self.ui.add_button.clicked.connect(self.printer)
can't be used if there's also, say, a
clicked(float, float)
so you'd have to fall back to the older style. It's always good to know both.
I know this post is pretty old, but I just stumbled across it,
maybe you will too and now this saves your day ;) ok...
by the way, it's my first post here on SO, yey!
WARNING, i did not test this code, i just copied some snippets of code i wrote some time ago, so, there may be some error, but I hope it helps anyway
PyQt's new style signals briefly:
# notice that the signal declarations are at class level (not inside some method)
class MyClass(QObject): # must subclass QObject (or subclass)
# declaring signals
mySimpleSignal = pyqtSignal()
mySignalWithArguments = pyqtSignal(int, list)
myOverloadedSignal = ([int, object],[str,object])
def __init__(self, parent=None):
super(MyClass,self).__init__(parent=parent) # remember to init the super class
[...]
# methods
[...]
# connecting signals
def connectSignalsMethod(self):
# connecting simple signal
self.mySimpleSignal.connect(self.mySlot)
# connecting signal with arguments
self.mySignalWithArguments.connect(self.mySlotWithArguments)
# connecting overloaded signals
self.myOverloadedSignal[int, object].connect(self.mySlot1)
self.myOverloadedSignal[str, object].connect(self.mySLot2)
# same syntax for disconnect()
# emitting signals
def emitSignalsMethod(self):
# emitting simple signal
self.mySimpleSignal.emit()
# emitting signal with arguments
self.mySignalWithArguments.emit(123,['this','is','a','list'])
# emitting overloaded signal
myOverloadedSignal[str,object].emit('this is a string', myObject)
# my slots
#pyqtSlot()
def mySlot(self):
print('hey!')
#pyqtSlot(int, list)
def mySlotWithArguments(self, someNumber, someList):
print('got a number: %d and a list: %s' % (someNumber, someList))
#pyqtSlot(int, object)
def mySlot1(self, intArg, objectArg):
print('got an int and an object')
#pyqtSlot(str, object)
def mySlot2(self, str, object):
print('got a string and an object')
# an overloaded slot
#pyqtSignal(int)
#pyqtSignal(str)
def overloadedSlot(someArgument)
print('got something: %s' % someArgument)
otherwise, try this
http://www.harshj.com/2010/05/06/pyqt-faq-custom-signals-jpeg-mouse-hovers-and-more/#custom
Edit:
events and signals are not the same, what you see above is about signals

Categories

Resources