[PySide] using QProcess to run python function

Frank Rueter | OHUfx frank at ohufx.com
Fri Mar 14 05:27:16 CET 2014


great, thanks Sean.
In order to communicate with the progress in each thread (to drive 
progress and catch finished and error events), should I use 
QtCore.QThread.currentThread() and hook up my slots to it's events?

Cheers and thanks a lot for bearing with me here.

frank


On 14/03/14 17:15, Sean Fisk wrote:
>
> Hi Frank,
>
> Glad you got that figured out. One more important thing:
>
> To achieve a "clean exit", you should wait for the completion of all 
> tasks associated with the |QThreadPool| before exiting. Use something 
> like:
>
> |thread_pool = QtCore.QThreadPool.globalInstance()
> thread_pool.start(hello)
> thread_pool.waitForDone()
> |
>
> It is a common idiom to have the application wait for this before it 
> exits:
>
> If you are using a |QApplication| or |QCoreApplication| (i.e., a Qt 
> event loop):
>
> |from  PySideimport  QtCore
> QtCore.QCoreApplication.instance().aboutToQuit.connect(thread_pool.waitForDone)
> |
>
> Or with Python's exit handlers:
>
> |import  atexit
> atexit.register(thread_pool.waitForDone)
> |
>
> In general, I would prefer Qt's method if you are running an event loop.
>
> Hope this helps!
>
>
>
> --
> Sean Fisk
>
>
> On Fri, Mar 14, 2014 at 12:00 AM, Frank Rueter | OHUfx 
> <frank at ohufx.com <mailto:frank at ohufx.com>> wrote:
>
>     False alarm:
>     Looks like the culprit wasn't the code but the debugger I was
>     using spat it's dummy more or less silently.
>     When I run the same code in a different interpreter it works as
>     expected.
>
>
>
>
>     On 14/03/14 14:30, Frank Rueter | OHUfx wrote:
>>     after a much longer absence from this than anticipated, I'm
>>     finally trying to get back into this.
>>     I had a look at your example Sean and it makes sense so far.
>>     Now I'm trying to follow your advise and use QThreadPool, but am
>>     not finding any good examples on it's usage.
>>     Unfortunately, the first example mentioned in the docs
>>     <http://srinikom.github.io/pyside-docs/PySide/QtCore/QThreadPool.html>
>>     already throws an error for me:
>>
>>     from PySide import QtCore
>>     class HelloWorldTask(QtCore.QRunnable):
>>         def run(self):
>>             print "Hello world from thread",
>>     QtCore.QThread.currentThread()
>>
>>     hello = HelloWorldTask()
>>     # QThreadPool takes ownership and deletes 'hello' automatically
>>     QtCore.QThreadPool.globalInstance().start(hello)
>>
>>     result:
>>     Hello world from thread
>>     Traceback (most recent call last):
>>       File "/ohufx/pipeline/tools/python/sandbox/QThreadPoolTest.py",
>>     line 6, in run
>>         print "Hello world from thread", QtCore.QThread.currentThread()
>>     AttributeError: 'NoneType' object has no attribute 'QThread'
>>
>>
>>
>>     What am I missing here?
>>
>>     Cheers,
>>     frank
>>
>>
>>
>>
>>
>>     On 28/01/14 08:00, Sean Fisk wrote:
>>>     On Sat, Jan 25, 2014 at 2:38 AM, Frank Rueter | OHUfx
>>>     <frank at ohufx.com <mailto:frank at ohufx.com>> wrote:
>>>
>>>         fantastic, thanks Sean!!
>>>         I will examine this to make sure I understand everything,
>>>         then give QThreadPool a whirl. Am more than happy to learn
>>>         from more experienced people and adjust my approaches
>>>         accordingly, so thanks a lot for your time with this!
>>>
>>>
>>>     No problem! Let me know if you have any questions about the code.
>>>
>>>
>>>         Cheers,
>>>         frank
>>>
>>>
>>>
>>>         On 25/01/14 20:03, Sean Fisk wrote:
>>>>
>>>>         Hi Frank,
>>>>
>>>>         I updated your example to hopefully work as you would like.
>>>>         I added a progress bar update as well. I'm going to make a
>>>>         last-ditch effort to convince you to stop doing things
>>>>         manually with |QThread|, and move to using |QThreadPool|
>>>>         <http://pyside.github.io/docs/pyside/PySide/QtCore/QThreadPool.html>.
>>>>         Everything about the |QThreadPool| API is much nicer, and
>>>>         it's worked much better for me in real projects. Also, the
>>>>         Python 's |multiprocessing|
>>>>         <http://docs.python.org/2/library/multiprocessing.html> and
>>>>         |concurrent.futures| <http://pythonhosted.org/futures/>
>>>>         modules can work well if you're careful about your callbacks.
>>>>
>>>>         Also, there is a large discussion about not overriding the
>>>>         |run()| method of |QThread|. I don't think overriding it is
>>>>         so bad if you don't need the thread to be running an event
>>>>         loop of its own. I still prefer the |QThreadPool| API,
>>>>         though. Someone please correct me if this is totally wrong
>>>>         and there is never a reason to override it.
>>>>
>>>>         Here is the code:
>>>>
>>>>         |#!/usr/bin/env python
>>>>
>>>>         import  sys
>>>>         import  time
>>>>
>>>>         from  PySideimport  QtGui
>>>>         from  PySideimport  QtCore
>>>>
>>>>         TOTAL_WIDGETS =10
>>>>
>>>>         class  Worker(QtCore.QObject):
>>>>              processed = QtCore.Signal(int)
>>>>              finished = QtCore.Signal()
>>>>
>>>>              # Overriding this is not necessary if you're not doing anything in it.
>>>>
>>>>              # def __init__(self):
>>>>              #     super(Worker, self).__init__()
>>>>
>>>>              def  helloWorld(self):
>>>>                  for  iin  xrange(TOTAL_WIDGETS):
>>>>                      # We sleep first to simulate an operation taking place.
>>>>                      time.sleep(0.5)
>>>>                      print  'hello %s'  % i
>>>>                      self.processed.emit(i +1)
>>>>                  # Must manually emit the finished signal.
>>>>                  self.finished.emit()
>>>>
>>>>         class  MainUI(QtGui.QWidget):
>>>>              def  __init__(self, parent=None):
>>>>                  super(MainUI, self).__init__(parent)
>>>>                  self.extraThread = QtCore.QThread()
>>>>
>>>>                  # IMPORTANT: Don't quit the app until the thread has completed. Prevents errors like:
>>>>                  #
>>>>                  #     QThread: Destroyed while thread is still running
>>>>                  #
>>>>                  QtGui.QApplication.instance().aboutToQuit.connect(self.quit)
>>>>
>>>>                  self.worker = Worker()
>>>>                  self.worker.moveToThread(self.extraThread)
>>>>                  self.setupUI()
>>>>                  self.connectSignalsAndSlots()
>>>>
>>>>              def  setupUI(self):
>>>>                  # CREAT MAIN LAYOUT AND WIDGETS
>>>>                  mainLayout = QtGui.QVBoxLayout()
>>>>                  btnLayout = QtGui.QHBoxLayout()
>>>>                  mainLayout.addLayout(btnLayout)
>>>>                  self.setLayout(mainLayout)
>>>>
>>>>                  self.progressBar = QtGui.QProgressBar(self)
>>>>                  self.progressBar.setRange(0, TOTAL_WIDGETS)
>>>>                  self.progressBar.setVisible(False)
>>>>                  self.btnWork = QtGui.QPushButton('Do Work')
>>>>                  self.btnCancel = QtGui.QPushButton('Cancel')
>>>>                  self.btnCancel.setDisabled(True)
>>>>
>>>>                  self.guiResponseProgressbar = QtGui.QProgressBar(self)
>>>>                  self.guiResponseProgressbar.setRange(0,0)
>>>>
>>>>                  self.outputWindow = QtGui.QTextEdit()
>>>>
>>>>                  mainLayout.addWidget(self.progressBar)
>>>>                  mainLayout.addWidget(self.outputWindow)
>>>>                  mainLayout.addWidget(self.guiResponseProgressbar)
>>>>
>>>>                  btnLayout.addWidget(self.btnWork)
>>>>                  btnLayout.addWidget(self.btnCancel)
>>>>
>>>>              def  connectSignalsAndSlots(self):
>>>>                  print  'connecting signals'
>>>>                  self.btnWork.clicked.connect(self.startWorker)
>>>>
>>>>                  # Pleas see <http://nooooooooooooooo.com/>. Bad bad bad bad bad.
>>>>                  # self.btnCancel.clicked.connect(self.extraThread.terminate)
>>>>
>>>>                  # THREAD STARTED
>>>>                  # Not necessary; just do this in startWorker.
>>>>                  # self.extraThread.started.connect(lambda: self.btnWork.setDisabled(True))
>>>>                  # self.extraThread.started.connect(lambda: self.btnCancel.setEnabled(True))
>>>>                  # self.extraThread.started.connect(self.progressBar.show)
>>>>                  self.extraThread.started.connect(self.worker.helloWorld)
>>>>
>>>>                  # THREAD FINISHED
>>>>                  # self.extraThread.finished.connect(lambda: self.btnCancel.setDisabled(True))
>>>>                  # self.extraThread.finished.connect(self.extraThread.deleteLater)
>>>>                  # self.extraThread.finished.connect(self.worker.deleteLater)
>>>>                  self.extraThread.finished.connect(self.finished)
>>>>
>>>>                  # Connect worker signals.
>>>>                  self.worker.processed.connect(self.progressBar.setValue)
>>>>                  self.worker.finished.connect(self.finished)
>>>>
>>>>                  # SHOW PROGRESS BAR WHEN PUBLISHING STARTS
>>>>                  # self.extraThread.started.connect(self.progressBar.show)
>>>>                  # CONNECT PROCESS TO PROGRESS BAR AND OUTPUT WINDOW
>>>>                  # NOT DONE YET
>>>>
>>>>              def  startWorker(self):
>>>>                  # GO
>>>>                  self.btnWork.setDisabled(True)
>>>>                  self.btnCancel.setEnabled(True)
>>>>                  self.progressBar.show()
>>>>                  print  'starting worker thread'
>>>>                  self.extraThread.start()
>>>>
>>>>                  # THIS IS BLOCKING THE GUI THREAD! Try putting this back in and seeing
>>>>                  # what happens to the gui_response_progressbar.
>>>>
>>>>                  # for i in xrange(10):
>>>>                  #     print 'from main thread:', i
>>>>                  #     time.sleep(.3)
>>>>
>>>>              def  finished(self):
>>>>                  print  'finished'
>>>>                  self.btnCancel.setDisabled(True)
>>>>                  # self.extraThread.deleteLater()
>>>>                  # self.worker.deleteLater()
>>>>
>>>>              def  quit(self):
>>>>                  # Quit the thread's event loop. Note that this *doesn't* stop tasks
>>>>                  # running in the thread, it just stops the thread from dispatching
>>>>                  # events.
>>>>                  self.extraThread.quit()
>>>>                  # Wait for the thread to complete. If the thread's task is not done,
>>>>                  # this will block.
>>>>                  self.extraThread.wait()
>>>>
>>>>         if  __name__ =='__main__':
>>>>              args = sys.argv
>>>>              app = QtGui.QApplication(args)
>>>>              p = MainUI()
>>>>              p.show()
>>>>              # Annoyance on Mac OS X.
>>>>              p.raise_()
>>>>              sys.exit(app.exec_())|
>>>>
>>>>         Cheers,
>>>>
>>>>
>>>>
>>>>         --
>>>>         Sean Fisk
>>>>
>>>>
>>>>         On Sat, Jan 25, 2014 at 12:30 AM, Frank Rueter | OHUfx
>>>>         <frank at ohufx.com <mailto:frank at ohufx.com>> wrote:
>>>>
>>>>             quick update:
>>>>             I just learnt about connection types but those didn't
>>>>             help either in this case:
>>>>             http://qt-project.org/doc/qt-5/threads-qobject.html#signals-and-slots-across-threads
>>>>
>>>>
>>>>
>>>>
>>>>             On 25/01/14 18:15, Frank Rueter | OHUfx wrote:
>>>>>             And of course I ran into trouble :-D
>>>>>             Here is my test code trying to ustilise QThread:
>>>>>             http://pastebin.com/Q26Q9M1M
>>>>>
>>>>>             The basic structure seems to work (the extra thread
>>>>>             and the main thread are running at the same time), but
>>>>>             my UI does not update according to the signal
>>>>>             connections, e.g.:
>>>>>             When the thread starts the progress bar is supposed to
>>>>>             be shown, the "Do Work" button should be disabled, the
>>>>>             "Cancel" button disabled.
>>>>>             etc.
>>>>>
>>>>>             I tried calling self.update() in the MainUI when the
>>>>>             thread starts  but to no avail.
>>>>>             I'm sure I'm missing something obvious as usual.
>>>>>
>>>>>             I tried to adhere to what I learnt on this list about
>>>>>             threading and avoid sub-classing QThread.
>>>>>
>>>>>             Cheers,
>>>>>             frank
>>>>>
>>>>>             On 24/01/14 17:41, Frank Rueter | OHUfx wrote:
>>>>>>             Great, thanks. I shall adjust my code.
>>>>>>             I am interested in seeing how you would go about it,
>>>>>>             but let me have a go from scratch, I will be able to
>>>>>>             understand things much better afterwards :)
>>>>>>
>>>>>>             Cheers,
>>>>>>             frank
>>>>>>
>>>>>>
>>>>>>             On 24/01/14 17:38, Sean Fisk wrote:
>>>>>>>             On Thu, Jan 23, 2014 at 10:44 PM, Frank Rueter |
>>>>>>>             OHUfx <frank at ohufx.com <mailto:frank at ohufx.com>> wrote:
>>>>>>>
>>>>>>>                 Much appreciated but as I mentioned, I think I
>>>>>>>                 jumped the gun with my post and should be using
>>>>>>>                 QThread to hook the python code to my
>>>>>>>                 QProgressBar and debug output window (QTextEdit).
>>>>>>>
>>>>>>>             That would be a correct way to use |QProgressBar|.
>>>>>>>             Also, for subprocess output, I would consider using
>>>>>>>             |QPlainTextEdit| instead of |QTextEdit| as is is
>>>>>>>             more performant with high amounts of text.
>>>>>>>
>>>>>>>             If you are interested, I just wrote an asynchronous
>>>>>>>             module for PySide for the project on which I am
>>>>>>>             currently working. It is based on Python's futures
>>>>>>>             <http://pythonhosted.org/futures/> module and works
>>>>>>>             great with Qt's signals/slots. Although the project
>>>>>>>             is primarily closed-source, I would be happy to
>>>>>>>             share the async implementation with you. I don't
>>>>>>>             know if would fit your needs, but for us it's much
>>>>>>>             easier than manually spawning |QThread|s and even
>>>>>>>             easier than |QThreadPool|.
>>>>>>>
>>>>>>>             Good luck!
>>>>>>>
>>>>>>>                 I will investigate that now
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>                 On 24/01/14 16:08, Sean Fisk wrote:
>>>>>>>>                 On Thu, Jan 23, 2014 at 9:42 PM, Frank Rueter |
>>>>>>>>                 OHUfx <frank at ohufx.com
>>>>>>>>                 <mailto:frank at ohufx.com>> wrote:
>>>>>>>>
>>>>>>>>                     Thanks Sean and Ryan,
>>>>>>>>
>>>>>>>>                     I'm still not quite clear on how this ties
>>>>>>>>                     into QProcess.start()
>>>>>>>>
>>>>>>>>
>>>>>>>>                 It doesn't tie in with |QProcess| at all. We're
>>>>>>>>                 advising to avoid using that :)
>>>>>>>>
>>>>>>>>                     I do have a if __name__ ... block in the
>>>>>>>>                     script in question.
>>>>>>>>                     An example would certainly be awesome, but
>>>>>>>>                     if it's less hassle, explaining how your
>>>>>>>>                     and Ryan's advise helps use QProcess on a
>>>>>>>>                     python module might already suffice. Maybe
>>>>>>>>                     a simlpe example says it all though?!
>>>>>>>>
>>>>>>>>
>>>>>>>>                 I will whip up a simple example for you, but it
>>>>>>>>                 might take a few hours (lots of stuff to do
>>>>>>>>                 right now).
>>>>>>>>
>>>>>>>>                     I'm not using python 3 btw
>>>>>>>>
>>>>>>>>                     Thanks guys for your help!!
>>>>>>>>
>>>>>>>>                     frank
>>>>>>>>
>>>>>>>>
>>>>>>>>                     On 24/01/14 15:33, Sean Fisk wrote:
>>>>>>>>>
>>>>>>>>>                     Hi Frank,
>>>>>>>>>
>>>>>>>>>                     You should definitely avoid calling Python
>>>>>>>>>                     as a subprocess if you can. As far as
>>>>>>>>>                     Ryan's example, I agree with the |if
>>>>>>>>>                     __name__...| but I think that using the
>>>>>>>>>                     |imp| module is a bit overkill. I would
>>>>>>>>>                     recommend using Setuptool's |entry_points|
>>>>>>>>>                     keyword
>>>>>>>>>                     <http://pythonhosted.org/setuptools/setuptools.html#automatic-script-creation>.
>>>>>>>>>                     Or distutils' |scripts| keyword
>>>>>>>>>                     <http://docs.python.org/2/distutils/setupscript.html#installing-scripts>,
>>>>>>>>>                     if you must.
>>>>>>>>>
>>>>>>>>>                     An example of a well-known Python package
>>>>>>>>>                     which does this is Pygments
>>>>>>>>>                     <https://bitbucket.org/birkenfeld/pygments-main>,
>>>>>>>>>                     which has a large "library" component but
>>>>>>>>>                     also comes with the |pygmentize|
>>>>>>>>>                     command-line script. The Pygments codebase
>>>>>>>>>                     is pretty large, so if you would like me
>>>>>>>>>                     to whip up a simpler example I'd be glad
>>>>>>>>>                     to do so.
>>>>>>>>>
>>>>>>>>>                     Cheers,
>>>>>>>>>
>>>>>>>>>                     --
>>>>>>>>>                     Sean Fisk
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>                     On Thu, Jan 23, 2014 at 9:17 PM, Frank
>>>>>>>>>                     Rueter | OHUfx <frank at ohufx.com
>>>>>>>>>                     <mailto:frank at ohufx.com>> wrote:
>>>>>>>>>
>>>>>>>>>                         Sorry if I'm being thick, but I'm not
>>>>>>>>>                         quite understanding how this helps to
>>>>>>>>>                         connect a python function to
>>>>>>>>>                         qprocess?! All your code does is
>>>>>>>>>                         execute the script, right?!
>>>>>>>>>                         I can already call myscript.main()
>>>>>>>>>                         straight up, but maybe I'm missing the
>>>>>>>>>                         point as I'm unfamiliar with the imp
>>>>>>>>>                         module.
>>>>>>>>>
>>>>>>>>>                         Let me elaborate a little bit more:
>>>>>>>>>                         myscript.main() calls a bunch of other
>>>>>>>>>                         python scripts that (directly or
>>>>>>>>>                         through other scripts again) execute
>>>>>>>>>                         external programs to do some
>>>>>>>>>                         conversion work. Those external
>>>>>>>>>                         programs spit out their progress to
>>>>>>>>>                         stdout which I can see fine when I run
>>>>>>>>>                         myscript.main() manually in a python
>>>>>>>>>                         terminal.
>>>>>>>>>
>>>>>>>>>                         Now I need run myscript.main() via
>>>>>>>>>                         QProcess and grab stdout to do be able
>>>>>>>>>                         to show a progress bar as well as show
>>>>>>>>>                         stdout and stderr in a debug window
>>>>>>>>>                         inside my QT code.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>                         Cheers,
>>>>>>>>>                         frank
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>                         On 24/01/14 14:58, Ryan Gonzalez wrote:
>>>>>>>>>>                         If you put an "if __name__ ==
>>>>>>>>>>                         '__main__'" and a main functions, you
>>>>>>>>>>                         could always import the script from
>>>>>>>>>>                         the GUI frontend. Example:
>>>>>>>>>>
>>>>>>>>>>                         myscript.py
>>>>>>>>>>
>>>>>>>>>>                         def main(argv):
>>>>>>>>>>                         do_cool_stuff()
>>>>>>>>>>                             return 0
>>>>>>>>>>
>>>>>>>>>>                         if __name__ == '__main__':
>>>>>>>>>>                         sys.exit(main(sys.argv))
>>>>>>>>>>
>>>>>>>>>>                         mygui.py(Python 2):
>>>>>>>>>>
>>>>>>>>>>                         import imp
>>>>>>>>>>
>>>>>>>>>>                         ...
>>>>>>>>>>
>>>>>>>>>>                         main = imp.load_module('myscript',
>>>>>>>>>>                         *imp.find_module('myscript'))
>>>>>>>>>>
>>>>>>>>>>                         main.main(my_argv)
>>>>>>>>>>
>>>>>>>>>>                         mygui.py(Python 3):
>>>>>>>>>>
>>>>>>>>>>                         import importlib.machinery
>>>>>>>>>>
>>>>>>>>>>                         main =
>>>>>>>>>>                         importlib.machinery.SourceFileLoader('myscript',
>>>>>>>>>>                         'myscript.py').load_module('myscript')
>>>>>>>>>>
>>>>>>>>>>                         main.main(my_argv)
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>                         On Thu, Jan 23, 2014 at 7:48 PM,
>>>>>>>>>>                         Frank Rueter | OHUfx <frank at ohufx.com
>>>>>>>>>>                         <mailto:frank at ohufx.com>> wrote:
>>>>>>>>>>
>>>>>>>>>>                             Hi all,
>>>>>>>>>>
>>>>>>>>>>                             I got a little code design question:
>>>>>>>>>>
>>>>>>>>>>                             I have a python script that does
>>>>>>>>>>                             a lot of file
>>>>>>>>>>                             processing/converting/uploading
>>>>>>>>>>                             etc and I'd like to write a decent
>>>>>>>>>>                             interface for it now.
>>>>>>>>>>                             The main goal is to be able to
>>>>>>>>>>                             show the user detailed info about the
>>>>>>>>>>                             current step and progress as well
>>>>>>>>>>                             as clean up properly in case the
>>>>>>>>>>                             whole
>>>>>>>>>>                             thing is cancelled.
>>>>>>>>>>
>>>>>>>>>>                             My existing python code needs to
>>>>>>>>>>                             stay independent of QT so any
>>>>>>>>>>                             application that supports python
>>>>>>>>>>                             can use it.
>>>>>>>>>>                             I am wondering now how to best
>>>>>>>>>>                             connect the python script and the
>>>>>>>>>>                             PySide
>>>>>>>>>>                             code. Should I just run the
>>>>>>>>>>                             script as an argument to the python
>>>>>>>>>>                             interpreter like I would with any
>>>>>>>>>>                             other program? E.g.:
>>>>>>>>>>
>>>>>>>>>>                             process = QtCore.QProcess(self)
>>>>>>>>>>                             process.start(<path_to_python>,
>>>>>>>>>>                             <path_to_python_script>)
>>>>>>>>>>
>>>>>>>>>>                             As simple as this seems, it feels
>>>>>>>>>>                             odd to use python to call itself
>>>>>>>>>>                             as an
>>>>>>>>>>                             external program.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>                             I'm happy to go that way but am
>>>>>>>>>>                             curious how others are doing this?!
>>>>>>>>>>
>>>>>>>>>>                             Cheers,
>>>>>>>>>>                             frank
>>>>>>>>>>
>>>>>>>>>>                             _______________________________________________
>>>>>>>>>>                             PySide mailing list
>>>>>>>>>>                             PySide at qt-project.org
>>>>>>>>>>                             <mailto:PySide at qt-project.org>
>>>>>>>>>>                             http://lists.qt-project.org/mailman/listinfo/pyside
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>                         -- 
>>>>>>>>>>                         Ryan
>>>>>>>>>>                         If anybody ever asks me why I prefer
>>>>>>>>>>                         C++ to C, my answer will be simple:
>>>>>>>>>>                         "It's
>>>>>>>>>>                         becauseslejfp23(@#Q*(E*EIdc-SEGFAULT.
>>>>>>>>>>                         Wait, I don't think that was
>>>>>>>>>>                         nul-terminated."
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>                         _______________________________________________
>>>>>>>>>                         PySide mailing list
>>>>>>>>>                         PySide at qt-project.org
>>>>>>>>>                         <mailto:PySide at qt-project.org>
>>>>>>>>>                         http://lists.qt-project.org/mailman/listinfo/pyside
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>             _______________________________________________
>>>>>>             PySide mailing list
>>>>>>             PySide at qt-project.org  <mailto:PySide at qt-project.org>
>>>>>>             http://lists.qt-project.org/mailman/listinfo/pyside
>>>>>
>>>>>
>>>>>
>>>>>             _______________________________________________
>>>>>             PySide mailing list
>>>>>             PySide at qt-project.org  <mailto:PySide at qt-project.org>
>>>>>             http://lists.qt-project.org/mailman/listinfo/pyside
>>>>
>>>>
>>>>             _______________________________________________
>>>>             PySide mailing list
>>>>             PySide at qt-project.org <mailto:PySide at qt-project.org>
>>>>             http://lists.qt-project.org/mailman/listinfo/pyside
>>>>
>>>>
>>>
>>>
>>
>>     -- 
>>     ohufxLogo 50x50 <http://www.ohufx.com> 	*vfx compositing
>>     <http://ohufx.com/index.php/vfx-compositing> | *workflow
>>     customisation and consulting
>>     <http://ohufx.com/index.php/vfx-customising>* *
>>
>>
>>
>>     _______________________________________________
>>     PySide mailing list
>>     PySide at qt-project.org  <mailto:PySide at qt-project.org>
>>     http://lists.qt-project.org/mailman/listinfo/pyside
>
>     -- 
>     ohufxLogo 50x50 <http://www.ohufx.com> 	*vfx compositing
>     <http://ohufx.com/index.php/vfx-compositing> | *workflow
>     customisation and consulting
>     <http://ohufx.com/index.php/vfx-customising>* *
>
>
>     _______________________________________________
>     PySide mailing list
>     PySide at qt-project.org <mailto:PySide at qt-project.org>
>     http://lists.qt-project.org/mailman/listinfo/pyside
>
>

-- 
ohufxLogo 50x50 <http://www.ohufx.com> 	*vfx compositing 
<http://ohufx.com/index.php/vfx-compositing> | *workflow customisation 
and consulting <http://ohufx.com/index.php/vfx-customising>* *

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/pyside/attachments/20140314/e36e58cb/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: image/png
Size: 2666 bytes
Desc: not available
URL: <http://lists.qt-project.org/pipermail/pyside/attachments/20140314/e36e58cb/attachment.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: image/png
Size: 2666 bytes
Desc: not available
URL: <http://lists.qt-project.org/pipermail/pyside/attachments/20140314/e36e58cb/attachment-0001.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: ohufxLogo_50x50.png
Type: image/png
Size: 2666 bytes
Desc: not available
URL: <http://lists.qt-project.org/pipermail/pyside/attachments/20140314/e36e58cb/attachment-0002.png>


More information about the PySide mailing list