Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Fusion: automatic installation of PySide2 #6111

Merged
merged 21 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
3b7382f
OP-7450 - WIP of new hook to install PySide2
kalisp Dec 21, 2023
70a11c6
Merge remote-tracking branch 'origin/develop' into enhancement/OP-745…
kalisp Jan 8, 2024
61d4841
OP-7450 - updates querying of PySide2 presence
kalisp Jan 8, 2024
a2e63bc
OP-7450 - typo
kalisp Jan 8, 2024
582b7a5
Merge remote-tracking branch 'origin/develop' into enhancement/OP-745…
kalisp Jan 8, 2024
a242723
OP-7450 - removed forgotten raise for debugging
kalisp Jan 8, 2024
65b7a6d
OP-7450 - double quotes
kalisp Jan 8, 2024
05ff927
OP-7450 - return if error
kalisp Jan 8, 2024
6c5ba33
OP-7450 - return False
kalisp Jan 8, 2024
f546b63
OP-7450 - added optionality for InstallPySideToFusion
kalisp Jan 9, 2024
2e7861f
Merge branch 'enhancement/OP-7450_Fusion-setup-PySide2' of https://gi…
kalisp Jan 9, 2024
edef54f
OP-7450 - updated querying of Qt
kalisp Jan 9, 2024
ee66b06
OP-7450 - fix unwanted change
kalisp Jan 9, 2024
dfa1cfc
Merge branch 'develop' into enhancement/OP-7450_Fusion-setup-PySide2
kalisp Jan 9, 2024
77c2a58
OP-7450 - added settings for legacy OP
kalisp Jan 9, 2024
c11b65c
Merge branch 'enhancement/OP-7450_Fusion-setup-PySide2' of https://gi…
kalisp Jan 9, 2024
28a412b
OP-7450 - use correct python executable name in Linux
kalisp Jan 9, 2024
eac5e29
OP-7450 - headless installation in Windows
kalisp Jan 10, 2024
f85e484
OP-7450 - Hound
kalisp Jan 10, 2024
c517b1b
Merge branch 'develop' into enhancement/OP-7450_Fusion-setup-PySide2
kalisp Jan 10, 2024
004da4a
Update openpype/hosts/fusion/hooks/pre_pyside_install.py
kalisp Jan 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions openpype/hosts/fusion/hooks/pre_fusion_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,8 @@ def execute(self):

self.launch_context.env[py3_var] = py3_dir

# for hook installing PySide2
self.data["fusion_python3_home"] = py3_dir

self.log.info(f"Setting OPENPYPE_FUSION: {FUSION_HOST_DIR}")
self.launch_context.env["OPENPYPE_FUSION"] = FUSION_HOST_DIR
152 changes: 152 additions & 0 deletions openpype/hosts/fusion/hooks/pre_pyside_install.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import os
import subprocess
import platform
from openpype.lib.applications import PreLaunchHook, LaunchTypes


class InstallPySideToFusion(PreLaunchHook):
"""Automatically installs Qt binding to fusion's python packages.

Check if fusion has installed PySide2 and will try to install if not.

For pipeline implementation is required to have Qt binding installed in
fusion's python packages.
"""

app_groups = {"fusion"}
order = 2
launch_types = {LaunchTypes.local}

def execute(self):
# Prelaunch hook is not crucial
try:
self.inner_execute()
except Exception:
self.log.warning(
"Processing of {} crashed.".format(self.__class__.__name__),
exc_info=True
)
raise
kalisp marked this conversation as resolved.
Show resolved Hide resolved

def inner_execute(self):
self.log.debug("Check for PySide2 installation.")

fusion_python3_home = self.data.get("fusion_python3_home")
if not fusion_python3_home:
self.log.warning("'fusion_python3_home' was not provided. "
"Installation of PySide2 not possible")
return

exe = "python.exe" if os.name == 'nt' else "python"
kalisp marked this conversation as resolved.
Show resolved Hide resolved
python_executable = os.path.join(fusion_python3_home, exe)

if not os.path.exists(python_executable):
self.log.warning(
"Couldn't find python executable for fusion. {}".format(
python_executable
)
)
return

# Check if PySide2 is installed and skip if yes
if self.is_pyside_installed(python_executable):
self.log.debug("Fusion has already installed PySide2.")
return

self.log.debug("Installing PySide2.")
# Install PySide2 in fusion's python
if platform.system().lower() == "windows":
result = self.install_pyside_windows(python_executable)
else:
result = self.install_pyside(python_executable)

if result:
self.log.info("Successfully installed PySide2 module to fusion.")
else:
self.log.warning("Failed to install PySide2 module to fusion.")

def install_pyside_windows(self, python_executable):
"""Install PySide2 python module to fusion's python.

Installation requires administration rights that's why it is required
to use "pywin32" module which can execute command's and ask for
administration rights.
"""
try:
import win32api
kalisp marked this conversation as resolved.
Show resolved Hide resolved
import win32con
import win32process
import win32event
import pywintypes
from win32comext.shell.shell import ShellExecuteEx
from win32comext.shell import shellcon
except Exception:
self.log.warning("Couldn't import \"pywin32\" modules")
return
kalisp marked this conversation as resolved.
Show resolved Hide resolved

try:
# Parameters
# - use "-m pip" as module pip to install PySide2 and argument
# "--ignore-installed" is to force install module to fusion's
# site-packages and make sure it is binary compatible
parameters = "-m pip install --ignore-installed PySide2"

# Execute command and ask for administrator's rights
process_info = ShellExecuteEx(
nShow=win32con.SW_SHOWNORMAL,
fMask=shellcon.SEE_MASK_NOCLOSEPROCESS,
lpVerb="runas",
lpFile=python_executable,
lpParameters=parameters,
lpDirectory=os.path.dirname(python_executable)
)
process_handle = process_info["hProcess"]
win32event.WaitForSingleObject(process_handle,
win32event.INFINITE)
returncode = win32process.GetExitCodeProcess(process_handle)
return returncode == 0
except pywintypes.error:
pass
kalisp marked this conversation as resolved.
Show resolved Hide resolved

def install_pyside(self, python_executable):
"""Install PySide2 python module to fusion's python."""
try:
# Parameters
# - use "-m pip" as module pip to install PySide2 and argument
# "--ignore-installed" is to force install module to fusion's
# site-packages and make sure it is binary compatible
args = [
python_executable,
"-m",
"pip",
"install",
"--ignore-installed",
"PySide2",
]
process = subprocess.Popen(
args, stdout=subprocess.PIPE, universal_newlines=True
)
process.communicate()
return process.returncode == 0
except PermissionError:
self.log.warning(
"Permission denied with command:"
"\"{}\".".format(" ".join(args))
)
except OSError as error:
self.log.warning(f"OS error has occurred: \"{error}\".")
except subprocess.SubprocessError:
pass

def is_pyside_installed(self, python_executable):
"""Check if PySide2 module is in fusion's pip list."""
args = [python_executable, "-c", "import PySide2"]
process = subprocess.Popen(args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
_, stderr = process.communicate()
stderr = stderr.decode()
if "ModuleNotFound" in stderr:
return False
return True