Cannot add item to itemgroups if itemchange() is defined (PyQt) - python

I'm building a PyQt QGraphicsView project where some QGraphicItems can be moved around between different QGraphicsItemGroups. For that, I use the addItemToGroup() method of the "new" parent itemGroup.
This works fine, but only so long as I do not define the itemChange() method in my custom child-item class. Once I define that method (even if I just pass the function call to the super class), the childItems will not be added to ItemGroups no matter what I try.
class MyChildItem(QtGui.QGraphicsItemGroup):
def itemChange(self, change, value):
# TODO: Do something for certain cases of ItemPositionChange
return QtGui.QGraphicsItemGroup.itemChange(self, change, value)
#return super().itemChange(change, value) # Tried this variation too
#return value # Tried this too, should work according to QT doc
Am I simply too stupid for properly calling a superclass method in Python, or is the problem somewhere in the QT / PyQT magic?
I use Python 3.3 with PyQt 4.8 and QT 5.

I had the exact same problem. Maybe this: http://www.mail-archive.com/pyqt#riverbankcomputing.com/msg27457.html answers some of your questions?
Seems like we might be out of luck in PyQt4.
Update:
Actually, just found a workaround:
import sip
def itemChange(self, change, value):
# do stuff here...
result = super(TestItem, self).itemChange(change, value)
if isinstance(result, QtGui.QGraphicsItem):
result = sip.cast(result, QtGui.QGraphicsItem)
return result
taken from here: http://www.mail-archive.com/pyqt#riverbankcomputing.com/msg26190.html
Maybe not the most elegant and general solution, but over here, it works -- I'm able to add QGraphicItems to QGraphicItemGroups again.

Related

Including a docstring in another docstring

Problem: I want to use one docstring in another docstring.
Suppose I have the following snippet:
def window(dimensions: tuple):
'''
Function to create an app window and return it
PARAMETERS
----------
dimensions : tuple
The width and height of the window to create
RETURNS
-------
display.Window
Class to implement a screen # Make this equal to Window.__doc__
'''
class Window:
'''
Class to implement a screen
'''
def __init__(self, dimensions: tuple):
pass
return Window(dimensions)
I want to automatically set the docstring for window to include the docstring for Window
I read that you can set the docstring manually, like so:
window.__doc__ = "".join((window.__doc__, Window.__doc__))
But it is only executed when the function is called.
Also, I could use decorators, but is there a simpler intuitive way to do this?
Bonus: Is there a way to decide exactly where in the docstring I can include another?
EDIT: So, it looks like there is a duplicate suggestion to this question, but since I specifically asked without decorators, that does make my question somewhat different. Also, my use of nested class in window means that any attempt to change __doc__:
inside of window: will not occur until function is called.
outside of window: will not run as Window is nested.
So this rules both these methods out, as things stand.
But the answer of course has to be one of these. So the answer is a duplicate, not the question. :P
Therefore, I had to restructure my code. See below.
Thanks to #aparpara, I found that answer (which didn't show up when I searched it online), and it made me realise there is (possibly?) no solution to my specific question.
Therefore, I had to remove the nested class to be able to access it outside the function.
Here is the final version.
# module display_module.py
class Window:
'''
Class to implement pygame's screen
'''
def __init__(self, dimensions: tuple):
pass
def window(dimensions: tuple):
'''
Function to create an app window and return it
PARAMETERS
----------
dimensions : tuple
The width and height of the window to create
RETURNS
-------
display.Window
{0}
'''
return Window(dimensions)
window.__doc__ = window.__doc__.format(Window.__doc__.strip())
Still open to any answers to the old question!

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.

Defining a class property within __init__ as opposed to within another class method -- python

EDIT
Note, it was brought to my attention that Instance attribute attribute_name defined outside __init__ is a possible duplicate, which I mostly agree with (I didn't come upon this because I didn't know to search for pylint). However, I would like to keep this question open because of the fact that I want to be able to reinitialize my class using the same method. The general consensus in the previous question was to return each parameter from the loadData script and then parse it into the self object. This is fine, however, I would still have to do that again within another method to be able to reinitialize my instance of class, which still seems like extra work for only a little bit more readability. Perhaps the issue is my example. In real life there are about 30 parameters that are read in by the loadData routine, which is why I am hesitant to have to parse them in two different locations.
If the general consensus here is that returning the parameters are the way to go then we can go ahead and close this question as a duplicate; however, in the mean time I would like to wait to see if anyone else has any ideas/a good explanation for why.
Original
This is something of a "best practices" question. I have been learning python recently (partially to learn something new and partially to move away from MATLAB). While working in python I created a class that was structured as follows:
class exampleClass:
"""
This is an example class to demonstrate my question to stack exchange
"""
def __init__( self, fileName ):
exampleClass.loadData( self, fileName )
def loadData( self, fileName ):
"""
This function reads the data specified in the fileName into the
current instance of exampleClass.
:param fileName: The file that the data is to be loaded from
"""
with open(fileName,'r') as sumFile:
self.name = sumFile.readLine().strip(' \n\r\t')
Now this makes sense to me. I have an init class that populated the current instance of the class by calling to a population function. I also have the population function which would allow me to reinitialize a given instance of this class if for some reason I need to (for instance if the class takes up a lot of memory and instead of creating separate instances of the class I just want to have one instance that I overwrite.
However, when I put this code into my IDE (pycharm) it throws a warning that an instance attribute was defined outside of __init__. Now obviously this doesn't affect the operation of the code, everything works fine, but I am wondering if there is any reason to pay attention to the warning in this case. I could do something where I initialize all the properties to some default value in the init method before calling the loadData method but this just seems like unnecessary work to me and like it would slow down the execution (albeit only a very small amount). I could also have essentially two copies of the loadData method, one in the __init__ method and one as an actual method but again this just seems like unnecessary extra work.
Overall my question is what would the best practice be in this situation be. Is there any reason that I should restructure the code in one of the ways I mentioned in the previous paragraph or is this just an instance of an IDE with too broad of a code-inspection warning. I can obviously see some instances where this warning is something to consider but using my current experience it doesn't look like a problem in this case.
I think it's a best practice to define all of your attributes up front, even if you're going to redefine them later. When I read your code, I want to be able to see your data structures. If there's some attribute hidden in a method that only becomes defined under certain circumstances, it makes it harder to understand the code.
If it is inconvenient or impossible to give an attribute it's final value, I recommend at least initializing it to None. This signals to the reader that the object includes that attribute, even if it gets redefined later.
class exampleClass:
"""
This is an example class to demonstrate my question to stack exchange
"""
def __init__( self, fileName ):
# Note: this will be modified when a file is loaded
self.name = None
exampleClass.loadData( self, fileName )
Another choice would be for loadData to return the value rather than setting it, so your init might look like:
def __init__(self, fileName):
self.name = self.loadData(fileName)
I tend to think this second method is better, but either method is fine. The point is, make your classes and objects as easy to understand as possible.

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

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.

Redefine a python function based on another class function based on type

I'm more of an engineer and less of a coder, but I know enough python and C++ to be dangerous.
I'm creating a python vector/matrix class as a helper class based upon numpy as well as cvxopt. The overall goal (which I've already obtained... the answer to this question will just make the class better) is to make dot products and other processes more unified and easier for numerical methods.
However, I'd like to make my helper class even more transparent. What I'd like to do is to redefine the cvxopt.matrix() init function based upon the current variable which was used. This is to say, if I have a custom matrix: "cstmat", I'd like the function "cvxopt.matrix(cstmat)" to be defined by my own methods instead of what is written in the cvxopt class.
In short, I'd like to "intercept" the other function call and use my own function.
The kicker, though, is that I don't want to take over cvxopt.matrix(any_other_type). I just want to redefine the function when it's called upon my own custom class. Is this possible?
Thanks,
Jon
You can do this, but it's not pretty.
You can do probably something along these lines:
cvxopt._orig_matrix = cvxopt.matrix
def my_matrix(*args, **kwargs):
if isinstance(arg[0], cstmat):
# do your stuff here
else:
cvxopt._orig_matrix(*args, **kwargs)
cvxopt.matrix = my_matrix
But you're probably better off finding a less weird way. And no guarantees that won't forget who "self" is.
Better would be to use inheritance! Kinda like this:
class Cstmat(cvsopt.matrix):
def __init__(self, ...):
pass
def matrix(self, arg):
if isinstance(arg, cstmat):
# do your stuff here
else:
cvsopt.matrix(arg)

Categories

Resources