Open jamanabanana opened 6 years ago
I'm not that familiar with PyInstaller, but Pyface and Traitsui use indirect importing of the backend toolkit via setuptools entrypoints, so I'm guessing that you probably need to tell PyInstaller to include the modules from the qt4 entry points in pyface
(https://github.com/enthought/pyface/blob/master/setup.py#L173) and traitsui
(https://github.com/enthought/traitsui/blob/master/setup.py#L147)
But there may be some other places as well where there is code doing differential imports of qt vs. wx; most likely in Envisage, Apptools and Mayavi as well. These currently don't use the extension point mechanisms, so there is no unified place to go looking for things, unfortunately.
I have added the modules you suggested but the problem persists. It just seems to me that it is looking somewhere that doesn't exist since it says traitsui.toolkits and there is no toolkits folder or file in traitsui folder.
The traitsui.toolkits
in this context is not a module, but the name of the setuptools/pkgresources entry point for the plugins.
Well I'm grasping at straws but I might have something...
Going through the traceback, I noticed that this all starts by trying to set a marker_color (in traitsui\editors\code_editor.py). Working my way down the rabbit hole, I found that the Color function/method (in traits\traits.py on line 1218) only makes reference to wxPython in the comments... Is there some issue where qt is not supported fully?
def Color ( *args, **metadata ):
""" Returns a trait whose value must be a GUI toolkit-specific color.
Description
-----------
For wxPython, the returned trait accepts any of the following values:
* A wx.Colour instance
* A wx.ColourPtr instance
* an integer whose hexadecimal form is 0x*RRGGBB*, where *RR* is the red
value, *GG* is the green value, and *BB* is the blue value
Default Value
-------------
For wxPython, 0x000000 (that is, white)
"""
from traitsui.toolkit_traits import ColorTrait
return ColorTrait( *args, **metadata )
No, just a stale docstring. The actual behavior is deferred to the selected toolkit.
Well where/what should I be looking for to know if I even have the plugin? As the error states, it can't find a traitsui.toolkits plugin for qt4, so how can I know where it is looking / what it is looking for? It doesn't list a file location or expected file name so I don't know how to proceed...
There should be a traitsui-<version>.egg-info/
directory under site-packages
. Inside of it should be a file named entry_points.txt
. That file should have contents like the following:
[traitsui.toolkits]
null = traitsui.null:toolkit
qt = traitsui.qt4:toolkit
qt4 = traitsui.qt4:toolkit
wx = traitsui.wx:toolkit
OK thank you. I see that text file, but there doesn't appear to be line breaks between the entries. Would that be an issue? I opened it with Notepad on Windows. However, when I copy it into here the line breaks appear.
[traitsui.toolkits]
null = traitsui.null:toolkit
qt = traitsui.qt4:toolkit
qt4 = traitsui.qt4:toolkit
wx = traitsui.wx:toolkit
But if I need to point to that file to freeze with the rest of the modules, the periods in the folder name are becoming an issue...
I would suggest looking into the PyInstaller documentation and other related resources about how it handles pkg_resources
entry points. This link seems like it might be relevant: https://pythonhosted.org/PyInstaller/hooks.html?highlight=pkg_resources
Including things accessed by pkg_resources
must be a fairly standard, if advanced, thing to do with PyInstaller so there should be information somewhere.
Well I was able to get around this issue, but I'm not sure what exactly is different. I ended up going to an Anaconda Python 3.5.5 environment and reinstalling a few different versions of everything until it worked. I also had to use cx_freeze instead of pyinstaller. I used all of the same hidden-imports/includes between cx_freeze and pyinstaller so the one must just be better at the indirect imports.
I encountered the same issue but without any solution at the moment. I need to make a standalone application with PyQt5, mayavi 4.6.1 traisui6.0.0 and a lot of others, using python 3.6. After some tries with PYinstaller without any success I tried cx_freeze. Here again after several tries I managed to get up to the same error as above (No trauitsui.toolkits plugin found for toolkit qt4). I've tried with qt instead of qt4 : same message... I've read plenty of posted issues without getting the solution to this one... I guess it can come from : os.environ['ETS_TOOLKIT'] ?
Using qt vs. qt4 shouldn't matter (they should import the same backend). Ensure that you tell cx_freeze to include the pyface.ui.qt4
package and its subpackages (even though you are targeting qt5, the qt4 backend works). Beyond that, I'm not sure, there are a lot of things that go on during toolkit initialization that could cause the import to fail, such as starting the application.
You might try setting the QT_API
environment variable to pyqt5
if it isn't already set.
Beyond that, I'm not familiar with cx_freeze, so I'm not sure what else to add.
Thanks for the quick answer but yes, the setup.py file include the following packages :
_package = ['pyface.ui.qt4', 'tvtk.vtk_module', 'matplotlib.backends.backend_qt5','pkg_resources._vendor',
'pkg_resources.extern','pygments.lexers', 'tvtk.pyface.ui.qt4',
'pyface.qt','pyface.qt.QtGui','pyface.qt.QtCore','numpy',
'matplotlib','mayavi', 'traits', 'traitsui', 'sip', 'packaging',
'traitlets', 'xlrd', 'scipy.linalg', 'scipy', 'pkg_resources._vendor']
excludes = ['gtk', 'Tkinter', 'wx']
includes = ['atexit', 'appdirs', 'PyQt5', 'PyQt5.QtCore', 'PyQt5.QtGui',
'PyQt5.QtWidgets', 'packaging.specifiers', 'traitsui.toolkit', 'scipy.linalg']_
The QT_API path is refered to pyqt5 indeed. I've tried many things and migth have missed coupled solutions somewhere. So If anyone has some other proposal I would be gratefull
You might need to have more PyQt5.*
includes. Pyface imports from various places to adapt the Qt5 API to be approximately compatible with the Qt4 API. Look in pyface.qt.Qt*
for what is actually imported. I would suspect that you will need at least PyQt5.Qt
, PyQt5.QtPrintSupport
and possibly PyQt5.QtWebEngine
and PyQt5.QtWebEngineWidgets
.
ETA: and possibly PyQt5.QtOpenGL
since you are using Mayavi (not sure about that one).
I've tried to had different modules with no success up to now. This is my setup.py
import sys
from cx_Freeze import setup, Executable
import os
import scipy
path = sys.path
# Dependencies are automatically detected, but it might need fine tuning.
package = ['pyface.ui.qt4', 'tvtk', 'pkg_resources._vendor',
'pkg_resources.extern','pygments.lexers', 'tvtk.pyface.ui.qt4',
'pyface.qt','numpy',
'matplotlib','mayavi', 'traits', 'traitsui', 'sip', 'packaging',
'traitlets', 'xlrd', 'scipy', 'scipy.linalg','PyQt5']
excludes = ['gtk', 'Tkinter', 'wx']
includes = ['matplotlib.backends.backend_qt5','tvtk.vtk_module', 'atexit', 'appdirs',
'packaging.specifiers', 'traitsui.toolkit', 'traitsui.toolkit_traits', 'mayavi.mlab',
'pyface.qt.QtCore','pyface.qt.QtGui', 'pyface.qt.QtNetwork', 'pyface.qt.QtOpenGL', 'pyface.qt.QtScript', 'pyface.qt.QtSvg', 'pyface.qt.QtTest', 'pyface.qt.QtWebKit',
'PyQt5.QtCore', 'PyQt5.QtGui', 'PyQt5.Qt', 'PyQt5.QtWidgets', 'PyQt5.QtOpenGL', 'PyQt5.QtSvg', 'PyQt5.QtTest',
'PyQt5.QtPrintSupport', 'PyQt5.QtWebEngine', 'PyQt5.QtWebEngineWidgets']
scipy_path = os.path.dirname(scipy.__file__)
includefiles = [(str(scipy_path), "scipy")]
build_exe_options = {"packages": package,
"excludes": excludes,
"includes": includes,
"include_files": includefiles,
"namespace_packages": ['mayavi']
}
os.environ['ETS_TOOLKIT'] = 'qt'
os.environ['TCL_LIBRARY'] = r'C:\\Users\\xf245257\\AppData\\Local\\Continuum\\anaconda3\\envs\\NatuVent_dev\\tcl\\tcl8.6'
os.environ['TK_LIBRARY'] = r'C:\\Users\\xf245257\\AppData\\Local\\Continuum\\anaconda3\\envs\\NatuVent_dev\\tcl\tk8.6'
filename = r'C:\\Users\\xf245257\\Documents\\FAURE\\Soft\\NatuVent_Jules\\NatuVent\\NatuVent.py'
icon_path = r'C:\\Users\\xf245257\\Documents\\FAURE\\Soft\\NatuVent_Jules\\NatuVent\\GUI\\logo_black.png'
base = None
if sys.platform == "win32":
base = "Win32GUI"
cible = Executable(
script = filename,
targetName='NatuVent.exe',
base = base,
)
setup(name = "NatuVent",
version = "0.1",
description = "NatuVent GUI for natural ventilation potential assessment!",
options = {"build_exe": build_exe_options},
executables = [cible])
there is no error during cx-freeze process but when lauching the .exe file I get the following window
So it also migth come from the MayaviQWidget which is a classe in my graphical_core script. The app include mayavi object into widget of PyQT. Do I have to include the prgm also in the setup ??? I'm a bit loss....
This looks like the problem is during the first import which decides the toolkit. Some suggestions:
ETS_DEBUG
environment variable - that should produce more verbose output during the toolkit selection process.os.environ['ETS_TOOLKIT'] = 'qt4'
(some of the upstream ETS packages may not recognise qt
as a valid value yet.os.environ['QT_API'] = 'pyqt5'
.The latter would look something like:
# set correct Qt version
import os
os.environ['QT_API'] = 'pyqt5'
# more informative error messages (remove when working)
os.environ['ETS_DEBUG'] = '1'
# set correct ETS toolkit version
from traits.etsconfig.api import ETSConfig
ETSConfig.toolkit = 'qt4' # this works even if using Qt5
# force setup of toolkit (optional, but this will fail early if not right)
import pyface.api
even if this doesn't work it should give you a better idea of what is going wrong.
Thanks again but I didn't manage to solve the issue... The os.environ['ETS_DEBUG'] = '1' gives me the "ModuleNotFounderror" from pyface.ui.qt4.expandable_panel.... Isn't it a path problem ? I've reversed some import between mayavi, traitsui and tvtk. because as I included some print the traitsui.toolkit.py and pyface.base_toolkit.py to follow the variables and their path I saw that while lauching my main prgm these three were going through the same prgm. The path for all three was .._lib\ntpath.py. And everything works perfectly when lauching the main prgm in a prompt console. After making the exe file, as I put mayavi at fisrst, the pyface.toolkit was not found, as I put tvtk import at first, it was tvtk.toolkit that was not found and, at last, if traitsui was the first import the traitsui.toolkit had pb. the path were for each 'xxx\build\exe.win-amd64-3.6\lib\library.zip\ntpath.pyc' but the path that are printed in the error figure I've added in the above message does not mention the build floder... Am I in a wrong way or is there simply a path problem during the .exe construction process ? I report errors in a separate file and this one is always empty (the process's going well for cx_freeze). An idea ?
The expandable_panel
is just noise - there's no Qt version of that widget, so you will get a complaint from the ETS_DEBUG
about that.
This is looking like an issue with pkg_resources
not working properly with cx_freeze
or vice-versa. It is looking for the toolkit plugin entrypoint in this line plugins = list(pkg_resources.iter_entry_points(entry_point, toolkit_name))
and getting nothing back. So you need to work out how to make pkg_resources
entry points work with cx_freeze. My guess is that you probably need to include the entry_points.txt
files in the egg_info directories that Robert mentioned above for at least pyface, traitsui, and possibly mayavi/tvtk.
Including entrypoints ought to be a fairly standard thing for cx_freeze, but google searches were not helping much.
It seems like cx_freeze is not compatible with standard pkg_resources entry points. See https://github.com/anthony-tuininga/cx_Freeze/issues/216 Thanks to @itziakos for digging this up.
thanks for the link, I'll asked how the solve the issue. The doc wasn't that clear for me on how can I specify particular conditions for cx_freeze.
Im' posting a nexw message on this issue. I've manage to get same error using cx_freeze and Pyinstaller. As above, depending on the import order (traitsui, mayavi and tvtk), I get RuntimeError: No xxxx.toolkits plugin found for toolkit qt4 with the xxx replaced by traitsui, pyface or tvtk.... I've include in the setup file for cx_freeze the above recommendations, but I didn't used the .spec file for pysinstaller as I don't really know what to specify on what part. Does anyone have any idea ? I've tryed to donwgrade to python 3.5 but with no success. I'll tryied python 3.5.5 as above. Thanks to this fex days pb I create several environment and i'm not using conda anymore (conflcit between pip and conda for the different environment.
I'm not hopeful that cx_freeze will work for you. For PyInstaller, something like the approach described in this issue https://github.com/pyinstaller/pyinstaller/issues/3050 might help (it will need to be more sophisticated, as instead of 'xxx.subcmd' in that example you have to handle 'pyface.toolkits', 'traitsui.toolkits', etc.)
We don't use Pyinstaller/cx_freeze/etc. for our application deployment, but we've had some internal discussions about how to handle this incompatibility with pkg_resources more gracefully within ETS code.
Do you have any other options for application deployment ? I learned about cx_freeze and pysintaller only last week, so I can change wihtou any pb !
One option, if you are willing to consider it, is to use the previous releases of TraitsUI, Pyface, and Mayavi - the pkg_resources changes are new in version 6. Unfortunately you will need to use Qt4 instead of Qt5, but things should otherwise work transparently. You will still need to tell PyInstaller about all the hidden imports.
I think PyInstaller may be your best bet to get something working; or Py2App if you want to deploy on MacOS.
I had the same problem with cz_freeze and traitsui (pyqt4 backend, on windows). I wrote an hugly hack to get it working:
PYTHON_INSTALL_DIR = os.path.dirname(os.path.dirname(os.__file__))
packages = ['apptools', 'configobj', 'envisage', 'mayavi', 'numpy', 'pygments','six', 'traits', 'traitsui','vtk','pyface']
base_path = os.path.join(PYTHON_INSTALL_DIR, 'Lib','site-packages')
folders = list(next(os.walk(base_path))[1])
folders = [fol for fol in folders if fol.endswith('-info')]
folders = [fol for fol in folders if fol.split('-')[0].lower() in packages ]
out = [f for f in folders]
folders = [os.path.join(base_path, fol) for fol in folders]
folders = [(fol, '.\\lib' + '\\' + out[k]) for k, fol in enumerate(folders)]
# Dependencies are automatically detected, but it might need fine tuning.
build_exe_options = {
"packages": ['sys', 'os', 'ctypes','platform', 'sip', 'shutil', 'numpy', 'traits', 'traits.api', 'mayavi', 'mayavi.core',
'traitsui','traitsui.qt4.toolkit',
'mayavi.core.ui', 'mayavi.core.ui.api', 'tvtk', 'tvtk.tools', 'tvtk.api', 'json', 'math', 'time', 'sqlite3', 'pyface', 'pyface.ui',
'pyface.ui.qt4',
'pkg_resources','pyface.qt.QtGui','pyface.qt.QtCore','pkg_resources._vendor','pkg_resources.extern',"tvtk.pyface.ui.qt4",
'pkg_resources._vendor','pkg_resources.extern',
'pkg_resources', 'pygments'],
"excludes": [],
"includes": [],
"include_files": folders
}
I had the same problem with cz_freeze, pyface and mayavi (pyqt5 backend, on windows). I guess the problem comes from that it use pkg_resources package that needs the .egg-info files to import the package. So I create a venv with all my dependancy on it, after I generate the build folder with the exe with this setup :
import os
from cx_Freeze import setup, Executable
import cx_Freeze.hooks
def hack(finder, module):
return
cx_Freeze.hooks.load_matplotlib = hack
import scipy
import matplotlib
import PyQt5.Qt
os.environ['ETS_TOOLKIT'] = 'qt4'
os.environ['QT_API'] = 'pyqt5'
scipy_path = os.path.dirname(scipy.__file__)
pyqt5_path = os.path.dirname(PyQt5.Qt.__file__)
build_exe_options = {"packages": ["sys", "os", "glob",'subprocess',"pyface.ui.qt4", "tvtk.vtk_module", "tvtk.pyface.ui.wx", "matplotlib.backends.backend_qt4",'pygments.lexers',
'tvtk.pyface.ui.qt4','pyface.qt','pyface.qt.QtGui','pyface.qt.QtCore',
'openpyxl','scipy','matplotlib','numpy','math','matplotlib','mayavi',"statistics","sympy","mplcursors","traitsui","pyface"],
"include_files": [(str(scipy_path), "scipy"), (str(pyqt5_path), "PyQt5.Qt"), (matplotlib.get_data_path(), "mpl-data")],
"includes":['mayavi','PyQt5'],
'excludes':'Tkinter',
"namespace_packages": ['mayavi']
}
executables = [
Executable('Test.py', targetName="Test.exe",base = 'Win32GUI',)
]
setup(name='Test',
version='1.0',
description='',
options = {"build_exe": build_exe_options},
executables=executables,
)
After I copied all the files from the folder venv\Lib\sites-packages
to build\exe\lib
It worked for me. Good luck :)
@jgwacyk i edited your comment and added formatting to make it easier to read. I hope that's okay.
@jgwacyk i edited your comment and added formatting to make it easier to read. I hope that's okay.
It's perfect. Thanks 👍
I had the same problem with cz_freeze, pyface and mayavi (pyqt5 backend, on windows). I guess the problem comes from that it use pkg_resources package that needs the .egg-info files to import the package. So I create a venv with all my dependancy on it, after I generate the build folder with the exe with this setup :
import os from cx_Freeze import setup, Executable import cx_Freeze.hooks def hack(finder, module): return cx_Freeze.hooks.load_matplotlib = hack import scipy import matplotlib import PyQt5.Qt os.environ['ETS_TOOLKIT'] = 'qt4' os.environ['QT_API'] = 'pyqt5' scipy_path = os.path.dirname(scipy.__file__) pyqt5_path = os.path.dirname(PyQt5.Qt.__file__) build_exe_options = {"packages": ["sys", "os", "glob",'subprocess',"pyface.ui.qt4", "tvtk.vtk_module", "tvtk.pyface.ui.wx", "matplotlib.backends.backend_qt4",'pygments.lexers', 'tvtk.pyface.ui.qt4','pyface.qt','pyface.qt.QtGui','pyface.qt.QtCore', 'openpyxl','scipy','matplotlib','numpy','math','matplotlib','mayavi',"statistics","sympy","mplcursors","traitsui","pyface"], "include_files": [(str(scipy_path), "scipy"), (str(pyqt5_path), "PyQt5.Qt"), (matplotlib.get_data_path(), "mpl-data")], "includes":['mayavi','PyQt5'], 'excludes':'Tkinter', "namespace_packages": ['mayavi'] } executables = [ Executable('Test.py', targetName="Test.exe",base = 'Win32GUI',) ] setup(name='Test', version='1.0', description='', options = {"build_exe": build_exe_options}, executables=executables, )
After I copied all the files from the folder
venv\Lib\sites-packages
tobuild\exe\lib
It worked for me. Good luck :)
For reference here, I did not use the setup file and I just simply copied all packages from site-package to the lib directory then it worked for me.
I had the same problem with cz_freeze, pyface and mayavi (pyqt5 backend, on windows). I guess the problem comes from that it use pkg_resources package that needs the .egg-info files to import the package. So I create a venv with all my dependancy on it, after I generate the build folder with the exe with this setup :
import os from cx_Freeze import setup, Executable import cx_Freeze.hooks def hack(finder, module): return cx_Freeze.hooks.load_matplotlib = hack import scipy import matplotlib import PyQt5.Qt os.environ['ETS_TOOLKIT'] = 'qt4' os.environ['QT_API'] = 'pyqt5' scipy_path = os.path.dirname(scipy.__file__) pyqt5_path = os.path.dirname(PyQt5.Qt.__file__) build_exe_options = {"packages": ["sys", "os", "glob",'subprocess',"pyface.ui.qt4", "tvtk.vtk_module", "tvtk.pyface.ui.wx", "matplotlib.backends.backend_qt4",'pygments.lexers', 'tvtk.pyface.ui.qt4','pyface.qt','pyface.qt.QtGui','pyface.qt.QtCore', 'openpyxl','scipy','matplotlib','numpy','math','matplotlib','mayavi',"statistics","sympy","mplcursors","traitsui","pyface"], "include_files": [(str(scipy_path), "scipy"), (str(pyqt5_path), "PyQt5.Qt"), (matplotlib.get_data_path(), "mpl-data")], "includes":['mayavi','PyQt5'], 'excludes':'Tkinter', "namespace_packages": ['mayavi'] } executables = [ Executable('Test.py', targetName="Test.exe",base = 'Win32GUI',) ] setup(name='Test', version='1.0', description='', options = {"build_exe": build_exe_options}, executables=executables, )
After I copied all the files from the folder
venv\Lib\sites-packages
tobuild\exe\lib
It worked for me. Good luck :)
This worked for me. jgwacyk you really are a lifesaver thanks a lot.
Thanks for the above tips. They were really helpful to get it working for me on both cx_Freeze and PyInstaller.
pyface.ui.qt4
to packages
, and the Pyface and Traitsui egg-info
folders to include_files
egg-info
folders for both Pyface and Traitsui to datas
There may be a more efficient way to add just the necessary files, but this way at least worked for me.
I want use traitsui .but I can't create exe use pyinstaller. because I get same mistake as above .can you help me .if can't slove this problem I clound direct use pyqt5..why
For PyInstaller, there was a SciPy tutorial last year that included PyInstaller instructions and examples, which may be useful: https://github.com/jonathanrocher/ets_tutorial
my python is 3.8.10 use https://github.com/jonathanrocher/ets_tutorial.the problem unsolved keyerror traitsui.toolkits
my pyinstaller process
361 INFO: PyInstaller: 4.10
361 INFO: Python: 3.8.10
1037 INFO: Platform: Windows-10-10.0.19042-SP0
1039 INFO: UPX is not available.
Traceback (most recent call last):
File "
Gracias por los consejos que dieron anteriormente. He tenido el mismo problema y he leído a cada uno de las respuestas, dando resultados muy favorables:
I'm not sure if this would fit better under pyinstaller or traitsui, but essentially when I try to build an exe using pyinstaller the resultant exe file raises an exception:
RuntimeError: No traitsui.toolkits plugin found for toolkit qt4
The first two lines of my program are:
The program works fine when run in a python environment, so think I just need to add a hidden-import, but I can't find what file it would be looking for since there is no toolkits folder or toolkits.py file in the traitsui folder, but there is a qt4 folder. It just doesn't seem to be looking there.
For reference, I am attempting to import mayavi but it always gets stuck on this step. Before I added the ETSConfig line, it was the same error but with null instead of qt4. The whole traceback is below: