I have a tool that opens via an exe that’s bundled by pyinstaller. When inside of the tool you can launch Maya 2022 via a subprocess Popen. I can get this to work when I run my tool from an IDE, but when I run it from the exe I get this error:
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
Available platform plugins are: minimal, offscreen, webgl, windows, direct2d.
Again, I’m only getting the error when I launch Maya from the tool when the tool is run from a PyInstaller bundled .exe (however, this doesn’t happen when I run the tool from an IDE). I should also note that this setup worked fine for Maya 2020, so I’m not sure what’s new in 2022 other than Python 3.
Code:
My code is structured like this:
maya_app.py
import os
import sys
import subprocess
from Qt import QtWidgets
class MainWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(MainWidget, self).__init__(parent)
# GUI
btn_launch = QtWidgets.QPushButton('say hey')
btn_launch.clicked.connect(self.on_say_hey)
# Layout
main_layout = QtWidgets.QHBoxLayout(self)
main_layout.addWidget(btn_launch)
self.setLayout(main_layout)
print('I should be alive')
def on_say_hey(self):
print('hey')
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MainWidget()
window.resize(100, 100)
window.show()
sys.exit(app.exec_())
userSetup.py
import os
import sys
import maya.cmds as mc
print('hey')
def tweak_launch(*args):
print('Startup sequence running...')
os.environ['mickey'] = '--------ebae--------'
print(os.environ['mickey'])
root_path = os.getenv('_MMM_ROOT_PATH')
main_app_path = os.path.join(root_path, 'internal_source')
if not root_path in sys.path:
sys.path.append(main_app_path)
from internal_source import maya_app
w = maya_app.MainWidget()
w.show()
print('window should be up')
mc.evalDeferred("tweak_launch()")
bundle.spec
# -*- mode: python ; coding: utf-8 -*-
#pyinstaller --noconfirm pyinst_windows.spec
block_cipher = None
added_files = [
('./scenes', 'scenes'),
('./scripts', 'scripts'),
# ('../../venv/Lib/site-packages/PySide2/QtWidgets.pyd', 'PySide2'),
('../../venv/Lib/site-packages/PySide2', 'PySide2'),
# ('../../venv/Lib/site-packages/PySide2/QtGui.pyd', 'PySide2')
]
a = Analysis(['launch_maya.py'],
pathex=[
'D:/GitStuff/mb-armada/example_files/exe_bundle',
'D:/GitStuff/mb-armada/vendor/Qt.py',
'D:/GitStuff/mb-armada/venv/Lib/site-packages',
],
binaries=[],
datas=added_files,
hiddenimports=['internal_source', 'internal_source.maya_app'],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='bundle',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='bundle')
launch_maya.py
import os
import sys
import subprocess
from Qt import QtWidgets
from internal_source import maya_app
from scripts import userSetup
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
# GUI
btn_launch = QtWidgets.QPushButton('launch maya')
btn_launch.clicked.connect(self.on_launch)
# Layout
main_layout = QtWidgets.QHBoxLayout(self)
main_layout.addWidget(btn_launch)
self.setLayout(main_layout)
# Root path exe vs ide
if getattr(sys, 'frozen', False):
self.root_path = sys._MEIPASS
else:
self.root_path = os.path.join(os.path.dirname(os.path.realpath(__file__)))
def _set_app_envs(self):
_envs = os.environ.copy()
_envs['MAYA_SCRIPT_PATH'] = os.path.join(self.root_path, 'scripts').replace('\\', '/')
# Python path envs
_python_path_list = [
'D:\\GitStuff\\armada-pipeline-alpha',
'D:\\GitStuff\\armada-pipeline-alpha\\vendor\stubs',
'D:\\GitStuff\\armada-pipeline-alpha\\vendor\Qt.py',
'D:\\GitStuff\\armada-pipeline-alpha\\packages',
'D:\\GitStuff\\armada-pipeline-alpha\\armada',
'D:\\GitStuff\\armada-pipeline-alpha\\example_files\\exe_bundle',
'C:\\Program Files\\Autodesk\\Maya2022\\Python37\\Lib\\site-packages',
'C:\\Program Files\\Autodesk\\Maya2022\\Python37\\DLLs',
os.path.join(self.root_path).replace('\\', '/'),
os.path.join(self.root_path, 'scripts').replace('\\', '/'),
os.path.join(self.root_path, 'internal_source').replace('\\', '/')
]
# PYTHONPATH exe vs ide
if getattr(sys, 'frozen', False):
_envs['PYTHONPATH'] = os.pathsep.join(_python_path_list)
# _envs['PYTHONHOME'] = 'C:\\Program Files\\Autodesk\\Maya2022\\bin'
# application path
sys.path.append(os.path.dirname(sys.executable))
# sys.path.append(_python_path_list[3])
# path_stuff = _envs['PATH']
# _envs['PATH'] = path_stuff + os.pathsep + _python_path_list[4]
# path_stuff = _envs['PATH']
# sys.path.insert(0, _python_path_list[1])
# sys.path.insert(0, _python_path_list[0])
# _envs['PATH'] = _python_path_list[1] + os.pathsep + _python_path_list[0] + os.pathsep + path_stuff
else:
_envs['PYTHONPATH'] += os.pathsep + os.pathsep.join(_python_path_list)
return _envs
def on_launch(self):
# Maya file path
file_path_abs = '{}/scenes/test.mb'.format(self.root_path).replace('\\', '/')
print(file_path_abs)
app_exe = r'C:/Program Files/Autodesk/Maya2022/bin/maya.exe'
_envs = self._set_app_envs()
self.pretty(_envs)
if os.path.exists(file_path_abs):
proc = subprocess.Popen(
[app_exe, file_path_abs],
env=_envs,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
print(proc.stdout.read())
print(proc.stderr.read())
print('opened')
def pretty(self, d, indent=0):
for key, value in d.items():
print('\t' * indent + str(key))
if isinstance(value, dict):
self.pretty(value, indent + 1)
else:
print('\t' * (indent + 1) + str(value))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = Widget()
window.resize(400, 400)
window.show()
sys.exit(app.exec_())