Python: How to correctly use external functions
Question: This is something I've seen a fair bit of documentation on but I can't get an
exact answer to this specific gap in my knowledge and I keep running into
walls because of it, nothing seems to really cover it on this level:

I have a few windows, all of them should be draggable, so I'm building a
utilities file. In this file I have this:

    
    
    def mouseMoveEvent(self, event):
        if self.moving: self.move(event.globalPos()-self.offset)
    
    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            self.moving = True; self.offset = event.pos()
    
    
    def mouseReleaseEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            self.moving = False
    

And this will work if I put it into a single file (and don't call from another
one) with the actual window.

The question is, how do I call to this from another file (the one that has the
UI window)?

I am calling to it by

    
    
     from utils import *
    

So technically those functions are all accessible simply by typing

    
    
    mouseReleaseEvent(x,x)
    

But I need the UI to import those functions, so in the main file after putting
up the 'from utils import *' I type:

    
    
    self.moving = False
    

But that errors no matter what I do. So the question is what is the proper way
to enclose the functions listed first (first code block) so that I can call to
them from within my UI file?

Here is my UI code:

    
    
        #!/usr/bin/env python
    
        import sys
        import os
        from PyQt4 import QtCore, QtGui
        from vibotCss import css
        from viUtils import *
    
        class viBadOSUI(QtGui.QDialog):
            def __init__(self):
                QtGui.QDialog.__init__(self)
                #setup window
                self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
                self.resize(300, 150)
                center(self)
                self.setMouseTracking(True)
    
    
    
                #additional code
                self.show()
                self.setStyleSheet(css)
    
    
    
        app = QtGui.QApplication(sys.argv)
        window = viBadOSUI()
        sys.exit(app.exec_())
    

I have large gaps in my Python knowledge due to learning and using it solely
from within Autodesk Maya for a long time - I am trying to bridge said gaps
now. Thank you for any help.


Answer: I think what you are looking for are mixins:

For example, in **viUtils.py** you could define:

    
    
    from PyQt4 import QtCore, QtGui
    
    class Draggable(object):
        def mouseMoveEvent(self, event):
            try:
                if self.moving:
                    self.move(event.globalPos()-self.offset)
            except AttributeError:
                pass
    
        def mousePressEvent(self, event):
            if event.button() == QtCore.Qt.LeftButton:
                self.moving = True; self.offset = event.pos()
    
        def mouseReleaseEvent(self, event):   
            if event.button() == QtCore.Qt.LeftButton:
                self.moving = False
    
    class Centerable(object):
        pass # add code here
    
    class CountdownTimer(object):
        pass # add code here
    

By bundling related methods together in mixins, you can add functionality to
your classes (windows) by simply adding the mixin(s) to the base classes:

    
    
    import sys
    import os
    from PyQt4 import QtCore, QtGui
    from vibotCss import css
    import viUtils
    
    class viBadOSUI(QtGui.QDialog, 
                    viUtils.Draggable, viUtils.CountdownTimer):
    
        def __init__(self):            
            QtGui.QDialog.__init__(self)
            #setup window
            self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
            self.resize(300, 150)
            center(self)  # You should probably make `center` a method instead of a function and call `self.center()` instead.
            self.setMouseTracking(True)
    
            #additional code
            self.show()
            self.setStyleSheet(css)
    
    app = QtGui.QApplication(sys.argv)
    window = viBadOSUI()
    sys.exit(app.exec_())
    

One thing I do not like about my code above is that I could not figure out how
to define a mixin (e.g. `Draggable`) with an `__init__` which gets called
automatically by `viBadOSUI.__init__`. Normally you would use `super` for
this, but it appears `QtGui.QDialog.__init__` does not itself call `super`.

(Actually, I think it might be possible to use `super` **if** you put the
mixins **before** `QtGui.QDialog`, but this relies on trickery which will
break once someone forgets that `QtGui.QDialog` must appear last in the list
of bases.)

Because I could not define an `__init__` method which would work robustly:

    
    
    class Draggable(object):
        def __init__(self):
            ...
            self.moving = False
    

I instead modified `mouseMoveEvent` to use a `try..except`. This is better
than adding `self.moving = False` directly to `viBadOSUI.__init__` because
this attribute is used only by Draggable, and therefore should be somehow
bundled with `Draggable`. Setting the mixin and then **also** having to
remember to initialize an attribute just so the mixin will work is ugly
programming.

Using `try..except` here is perhaps slightly better than using `if
hasattr(self, 'moving')` since the try is quicker as long as an exception is
not raised, and the exception will be raised only at the beginning before the
first mousePressEvent.

Still, there is room for improvement and I hope someone here will show us a
better way.

An alternative approach would have been to define

    
    
    class viBadOSUI(QtGui.QDialog):
        mouseMoveEvent = viUtils.mouseMoveEvent
        mousePressEvent = viUtils.mousePressEvent
        mouseReleaseEvent = viUtils.mouseReleaseEvent
    

This gives you a lot of flexibility to add exactly those methods you want from
viUtils directly into any class you define. However, I think it is a bit too
much flexibility since mouseMoveEvent, mousePressEvent, and mouseReleaseEvent
seem "bundled" to me. They all work together to implement a single piece of
functionality. This is why I like the mixin approach better. Also, adding
`viUtils.Draggable` to the base classes is less typing than adding those 3
lines to every window subclass that you want to be draggable.

By the way, I'd recommend eschewing `from viUtils import *` and using `import
viUtils` instead. It will keep your code more organized in the long run.

