Unable to see app windows created by PySide2 in Spyder - python

I'm trying to run an app with PySide2 from Spyder 3.2.8 and Python 3.6.4 in Anaconda in a macOS 10.13.4.
attempt N°1
After having seen this stackoveflow page and this github page I changed my graphic backend from Inline to Automatic in Python > Preferences > IPython Console > Graphics and I tried to run the following script (script N°1):
script N°1
import sys
from PySide2.QtWidgets import *
# Create a Qt application
app = QApplication.instance()
if app is None:
print("print something")
app = QApplication(sys.argv)
# Create a Label and show it
label = QLabel("Hello World")
label.show()
# Enter Qt application main loop
app.exec_()
but got the following error message after running it:
Importing PySide2 disabled by IPython, which has
already imported an Incompatible QT Binding: pyqt5
There are similar reported issues here with matplotlib and here with ipython but it didn't help me (or I couldn't implement it properly). Then I tried to implement the content of this page about qtpy by changing the script N°1 in the following way:
script N°2
import os
os.environ['QT_API'] = 'pyside2'
from qtpy.QtWidgets import *
import sys
# Create a Qt application
app = QApplication.instance()
if app is None:
print("print something")
app = QApplication(sys.argv)
# Create a Label and show it
label = QLabel("Hello World")
label.show()
# Enter Qt application main loop
app.exec_()
attempt N°2
With Inline selected in Python > Preferences > IPython Console > Graphics. When I ran the script N°2 , the app launches and I got print something printed in to the console. When closing the app, I got Out[1]: 0 in the console. However when I run the script again, no error message appears in the console but the window of the app doesn't show-up
attempt N°3
This time with Automatic selected in Python > Preferences > IPython Console > Graphics. When I ran the script N°2 the first time, the app didn't launch and I got the following error message
/anaconda3/lib/python3.6/site-packages/qtpy/__init__.py:178: RuntimeWarning: Selected binding "pyside2" could not be found, using "pyqt5"
'using "{}"'.format(initial_api, API), RuntimeWarning)
Out[2]: -1
attempt N°4
With Automatic selected in Python > Preferences > IPython Console > Graphics. When I ran the script N°1 after having changed the line from PySide2.QtWidgets import * to from PyQt5.QtWidgets import *: The app didn't launch and I got the following error message
Out[1]: -1
attempt N°5
With Inline selected in Python > Preferences > IPython Console > Graphics. When I ran the script N°1 after having changed the line from PySide2.QtWidgets import * to from PyQt5.QtWidgets import *: The app launches and I got print something printed in to the console. I closed the app and got Out[1]: 0 in the console. However when I run the script again, no error message appears in the console but the window of the app doesn't show-up
N.B. this question is the continuation of that question

(Spyder maintainer here) Since the ipykernel package (which is used by Spyder to run code in its consoles) doesn't have event loop support for PySide2 as of May/2018 (as can be seen here), you won't be able to run PySide2 code inside Spyder, no matter what you try.
Notes:
The Automatic backend tries to select a suitable event loop for you, in this order: Qt5, Qt4, Tk and Inline. That's why it doesn't work in your case.
Every time you change a Graphics backend in Spyder, you need to restart the kernel of the console you want to run your code in. That's because you can only use one backend per console session (this is a limitation imposed by ipykernel, not by us). It's clear from your question that you're not doing that.
We're aware we fail to inform users when a kernel restart is necessary. We'll try to address that in our next major version (Spyder 4), to be released in 2019.
If you already know about qtpy, please use it to develop your apps instead of using PySide2 directly. That way you could work with PyQt5 for development in Spyder, but PySide2 for deployment, since qtpy takes care of working seamlessly with whatever binding is available.

Related

Win10 starting Python PyQt5 application using shortcut

Simply stated I have a simple python application which generates random passwords. This application was originally written using Tkinter and currently works. I am trying to improve the GUI interface by employing PyQt5. My efforts, so far have resulted in an application that runs from within my IDE (Spyder) and can also be run by invoking python from the commandline with the fullpath of the python script.
It should be noted this works for the Tkinter as well as the PyQt implementation.
My next step was to define a shortcut on the desktop to execute this script and have a window appear allowing creation of a password. The shortcut for the Tkinter script performs as expected and results in a window appearing. The script for the PyQt5 based script does not work. The only differences between the scripts are the target files being invoked by the script. Also both script files are in the same directory. This is a side by side image of the shortcut properties.
Here is a very simplistic example of the Puqt5 code. This code exhibits the same characteristics as the original in that it runs in the IDE as well as directly from Python in the CMD window but will not execute from a shortcut icon.
"""
Created on Wed Sep 9 10:37:46 2020
"""
import sys
from PyQt5.QtWidgets import QApplication, QWidget
def main():
app = QApplication(sys.argv)
w = QWidget()
w.resize(250, 150)
w.move(300, 300)
w.setWindowTitle('Simple')
w.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Has anyone else had this type of problem or can anyone suggest an approach for determining what is the cause and solution
everything works on Windows 7
It work when invoked from a shortcut on Win &, hmm that's very strange.
I tested it on Windows 10 also works.
Thanks for the helpful suggestions as well as your efforts to test this problem on your own systems. I finally found an answer that satisfies my needs. I used pyinstaller to create an executable and then launch the executable from a desktop shortcut. This works, so I am considering my question closed.

PyInstaller app keeps opening itself while using pyQode

Problem: The following program is keep starting itself every 5 seconds after making it executable using PyInstaller. It keeps running itself again and again. The code works fine without making if I run it directly using python.
I spent more than a day to fix this issue but no luck so far.
I tried it on Windows and Mac. Python version 3.7, PyInstaller Version 3.5 & 3.6.
PyInstaller Command:
pyinstaller --onefile generic_code_edit.py
Python Code:
import logging
logging.basicConfig(level=logging.DEBUG)
import sys
from pyqode.qt import QtWidgets
from pyqode.core.widgets import GenericCodeEdit
def main():
app = QtWidgets.QApplication(sys.argv)
# create editor and window
window = QtWidgets.QMainWindow()
editor = GenericCodeEdit()
# open a file
editor.file.open(__file__)
window.setCentralWidget(editor)
# run
window.show()
app.exec_()
editor.file.close()
if __name__ == "__main__":
main()
The Debug log:
DEBUG:pyqode.core.cache:getting encoding for generic_code_edit.py
DEBUG:pyqode.core.managers.file:mimetype detected: text/x-python
DEBUG:pyqode.core.managers.file:file open: generic_code_edit.py
ERROR:pyqode.backend:DEBUG:pyqode.qt:importing PyQt5
ERROR:pyqode.backend:DEBUG:pyqode.qt:imported PyQt5
ERROR:pyqode.backend:INFO:pyqode.qt:using pyqt5
ERROR:pyqode.backend:DEBUG:pyqode.core.cache:getting encoding for
generic_code_edit.py
ERROR:pyqode.backend:DEBUG:pyqode.core.managers.file:mimetype
detected: text/x-python
ERROR:pyqode.backend:DEBUG:pyqode.core.managers.file:file open:
generic_code_edit.py
Update:
Finally I found the problem. It is related to the autocomplete feature. This feature does not load perfectly with pyinstaller and cause a new start. Although I could not be able to make it working with pyinstaller, but I have been able to stop these feature to solve the starting loop issue.
I have passed an empty server file as backend to solve the issue. But still I want to make the Autocomplete working with pyinstaller.
editor = GenericCodeEdit(None, 'empty_file.py')

Why does PyQt4 behave differently between Jupyter and IPython notebook?

I have created a large python program with GUI based on PyQt4. I would like the package to run both in an IPython notebook (old installation with Python 2.7 on windows), Jupyter notebook (Python 3.5 installed recently with Anaconda), and as a python program passed on the command line. I'm having problems in running the code in Jupyter notebook (see directly at the bottom).
My module mymodule.py looks like this (extremely simplified, about 10k lines before the show from many other python files):
from PyQt4 import QtCore, QtGui
class MyModule(object):
def __init__(self):
self.window = QtGui.QMainWindow()
self.window.show()
The typical usage from command line is
python myscript.py
with the following file myscript.py
from PyQt4 import QtCore, QtGui
import mymodule
m = mymodule.MyModule()
APP = QtGui.QApplication.instance()
APP.exec_()
This works fine. I understand that APP.exec_() is needed to start some kind of EventLoop that works through the Gui interaction events.
In an IPython notebook, the user typically does
import mymodule
m = mymodule.MyModule() # opens the gui
# this still leaves the console active to allow things like this:
m.change_color("red")
I can run this without problems, where I understant that IPython somehow takes care of the EventLoop behind the scene.
Now, running the same commands in Jupyter notebook, a window opens, but freezes before allowing any user interaction. So I believe that Jupyter notebook does not treat the events properly because I did not tell it to do so. One way I have found is executing the command %pylab before running my code. However, I frequently run into related problems with this, for example when running %pylab and %matplotlib inline in direct succession before starting my program, this leads to freezing again once I load my code (curiously, reversing the order of the two magical commands works again). Also, I do not want to force the user of my program to execute %pylab in each new notebook if it can be avoided (also because I believe this requires a matlab installation, which is not a requirement of my program).
What code must I add in mymodule.py to make things compatible with the described user code in Jupyter notebook? Can anyone explain more clearly how IPython notebook and Jupyter notebook manage the QEventLoop/QApplication (or whatever is the important concept here) differently, and how the magic commands mess with this? I am afraid of hidden bugs in my program because of this, and would like to make it as robust as possible to not frustrate the users.
Here is a working solution that allows to run the code without distinguishing between different IPython / Jupyter versions and 'raw' Python. My __init__.py file contains this section at the beginning:
# enable IPython QtGui support if needed
try:
from IPython import get_ipython
get_ipython().magic('gui qt')
except BaseException as e:
# issued if code runs in bare Python
print('Could not enable IPython gui support: %s.' % e)
# get QApplication instance
from PyQt4 import QtCore, QtGui
APP = QtGui.QApplication.instance()
if APP is None:
print('Creating new QApplication instance "mymodule"')
APP = QtGui.QApplication(['mymodule'])
The script running on raw Python then only needs this:
import mymodule # imports the above code
from PyQt4 import QtCore, QtGui
if __name__ == '__main__':
QtGui.QApplication.instance().exec_()
I found no use case where this does not work.

PyDev doesn't recognise PyQt5

I am following a tutorial on pyqt, and got this code:
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
cb = QCheckBox('Show title', self)
cb.move(20, 20)
cb.toggle()
cb.stateChanged.connect(self.changeTitle)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Checkbox')
self.show()
def changeTitle(self, state):
if state == Qt.Checked:
self.setWindowTitle('Checkbox')
else: self.setWindowTitle('Unchecked!')
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I'm using PyDev on Eclipse. Suffice it to say that the code runs fine, but what is awkward is that PyDev underlines anything Qt/Q with a red line which when hovered over says Undefined variable: <..>. If it is undefined then how is it that my code runs without errors? Clearly this ought to be a problem with PyDev. I've removed the python interpreter (it was pointing to python2.7 instead of 3.4) and readded it as the correct version; but that didn't work. Interestingly enough, it recognises PyQt4 and insists on using widgets from that instead of PyQt5.
Just so you guys are aware, the code sample above is from another laptop which had PyQt5 as well. Both projects were from PyDev, and both had Ubuntu 15.04. It's possible that my importing of the project on my current machine messed up PyDev parsing the required libraries. Does anyone have a solution as to why PyDev doesn't recognise PyQt5?
I had the same problem. These steps worked for me.
Set the environment variable: export QT_API=pyqt5 (or whatever as appropriate)
restart eclipse so that picks up the new environment setting, and then add PyQt5 to the list of forced builtins for the interpreter (Window->preferences->pydev->interpreters->python interpreters) or look here http://www.pydev.org/manual_101_interpreter.html for more details.
The following SO question tipped me off to the presence of the variable: Setting up IPython Qtconsole with PyQt5. Before I set it, I as able to get some completion to work just by adding 'PyQt5' to the builtins, but it would not, for example, provide the full list of completions to something likefrom PyQt5.QtGui import, even though ipython stand-alone would. Further, the python console in pydev had the same problem and calling module_completion("from PyQt5.QtGui import Q") from Ipython.core.completerlib produced the same incomplete list. In the end, I guessed that since pydev was loading PyQt4 for the gui event loop (also configurable in the interpreter settings), there was a namespace conflict when it tried to introspect the Qt5 modules, causing it to bail out before it could build the full list of completions. Setting the environment variable causes pydev to load pyqt5 instead of the default pyqt4. I haven't checked, but it seems likely that set this way pydev will have problems completing pyqt4 references.
For all those lonesome internet wanderers trying to figure out how to integrate eclipse, pydev, and pyqt5 on Linux, I bring you my method from start to finish.
Eclipse, PyQt5, and PyDev on Linux
Install python v3.6
Install eclipse from eclipse.org
In eclipse, click Help->Install New Software
Click Add...
Add in software source "http://www.PyDev.org/updates" to the available software sources
Call it PyDev
Click on PyDev checkbox
Install it by clicking Next
Download PyQt5
Download SIP
Install SIP first
Install PyQt5
Reconfigure eclipse to use PyQt5
Click on Window→Preferences→PyDev→Interpreters→Python Interpreters
Click on Advanced Auto-Config
Rename interpreter to “python3.6”
Click on Libraries tab
Click on New Folder
Add in “/usr/lib/x86_64-linux-gnu/qt5/plugins”
Add in “/usr/lib/x86_64-linux-gnu/qt5/libexec”
Add in “/usr/lib/x86_64-linux-gnu/qt5/bin”
Click Apply
Click Apply and Close
Restart eclipse
Profit!
This will allow you to get the tab code completion in eclipse when developing pyqt5 applications.

PyQt app doesn't exit when i close the window

Whenever i execute the code and close the window, it closes,but the python console in the IDE doesn't return the exit code,when i try to run it again i get a warning dialog that says something like
No python console is selected to run main.py
So i have to close the IDE python console, and open a new one, then run the program in the new python console
I'm using spyder IDE 64 bits on windows
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
if __name__ == "__main__":
app = QApplication(sys.argv)
win = QMainWindow()
win.show()
sys.exit(app.exec_())
If you execute the code in a running (i)python console, you do not need to start a qapplication in the usual way, the two lines
win = QMainWindow()
win.show()
will be enough to get you running. This is because the console already has a (threaded) qapplication prepared for you.
The error message can be caused when no console has focus (i.e., perhaps the one you were using quit because of sys.exit(), or you clicked away etc). You need to simply click in an (i)python console to get it to be 'selected', and then the run button should work again.

Categories