Unable to launch Maya 2022 using Popen from a PyInstaller .exe

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:
image

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_())

For clarification, is the standalone GUI tool running, but causing this error when you try to launch maya through it, or is it failing to load the standalone tool altogether?

The former - I can launch my GUI just fine, it just fails to launch Maya when I press “launch Maya” button.

The first thought that comes to mind is that both the standalone UI and Maya have their own packaged Qt libraries and perhaps the Maya app is inheriting something from the environment that is causing it to point to the wrong library.

Does it help if you add these creationflags to subprocess.Popen?

creationflags=subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP

This is just a guess at the moment

QT_QPA_PLATFORM_PLUGIN_PATH point error
add in maya.env script will slove
QT_QPA_PLATFORM_PLUGIN_PATH = C:\Program Files\Autodesk\Maya2020\plugins\platforms

3 Likes