From ea72a254e2a40aa0dde9a0fa2a25d9c9f9bdb47b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 12 Feb 2021 17:22:28 +0100 Subject: [PATCH 1/3] modified prelaunch hooks for harmonmy, photoshop and after effects --- pype/hooks/aftereffects/pre_launch_args.py | 44 +++++++++++----------- pype/hooks/harmony/pre_launch_args.py | 39 +++++++++++-------- pype/hooks/photoshop/pre_launch_args.py | 44 +++++++++++----------- 3 files changed, 70 insertions(+), 57 deletions(-) diff --git a/pype/hooks/aftereffects/pre_launch_args.py b/pype/hooks/aftereffects/pre_launch_args.py index 00b35574298..340fa8c9dba 100644 --- a/pype/hooks/aftereffects/pre_launch_args.py +++ b/pype/hooks/aftereffects/pre_launch_args.py @@ -1,6 +1,10 @@ import os -from pype.lib import PreLaunchHook +import avalon +from pype.lib import ( + PreLaunchHook, + get_pype_execute_args +) class AfterEffectsPrelaunchHook(PreLaunchHook): @@ -12,29 +16,22 @@ class AfterEffectsPrelaunchHook(PreLaunchHook): app_groups = ["aftereffects"] def execute(self): - # Pop tvpaint executable - aftereffects_executable = self.launch_context.launch_args.pop(0) + # Pop executable + executable_path = self.launch_context.launch_args.pop(0) # Pop rest of launch arguments - There should not be other arguments! remainders = [] while self.launch_context.launch_args: remainders.append(self.launch_context.launch_args.pop(0)) + script_path = self.get_launch_script_path() + new_launch_args = get_pype_execute_args( + "run", script_path, executable_path + ) + # Add workfile path if exists workfile_path = self.data["last_workfile_path"] - if not os.path.exists(workfile_path): - workfile_path = "" - - new_launch_args = [ - self.python_executable(), - "-c", - ( - "import avalon.aftereffects;" - "avalon.aftereffects.launch(\"{}\", \"{}\")" - ).format( - aftereffects_executable.replace("\\", "\\\\"), - workfile_path.replace("\\", "\\\\") - ) - ] + if os.path.exists(workfile_path): + new_launch_args.append(workfile_path) # Append as whole list as these arguments should not be separated self.launch_context.launch_args.append(new_launch_args) @@ -46,7 +43,12 @@ def execute(self): ).format(str(remainders))) self.launch_context.launch_args.extend(remainders) - def python_executable(self): - """Should lead to python executable.""" - # TODO change in Pype 3 - return os.environ["PYPE_PYTHON_EXE"] + def get_launch_script_path(self): + """Path to launch script of photoshop implementation.""" + avalon_dir = os.path.dirname(os.path.abspath(avalon.__file__)) + script_path = os.path.join( + avalon_dir, + "AfterEffects", + "launch_script.py" + ) + return script_path diff --git a/pype/hooks/harmony/pre_launch_args.py b/pype/hooks/harmony/pre_launch_args.py index a61977f4e74..619c91a5224 100644 --- a/pype/hooks/harmony/pre_launch_args.py +++ b/pype/hooks/harmony/pre_launch_args.py @@ -1,6 +1,10 @@ import os -from pype.lib import PreLaunchHook +import avalon +from pype.lib import ( + PreLaunchHook, + get_pype_execute_args +) class HarmonyPrelaunchHook(PreLaunchHook): @@ -12,22 +16,22 @@ class HarmonyPrelaunchHook(PreLaunchHook): app_groups = ["harmony"] def execute(self): - # Pop tvpaint executable - harmony_executable = self.launch_context.launch_args.pop(0) + # Pop executable + executable_path = self.launch_context.launch_args.pop(0) # Pop rest of launch arguments - There should not be other arguments! remainders = [] while self.launch_context.launch_args: remainders.append(self.launch_context.launch_args.pop(0)) - new_launch_args = [ - self.python_executable(), - "-c", - ( - "import avalon.harmony;" - "avalon.harmony.launch(\"{}\")" - ).format(harmony_executable.replace("\\", "\\\\")) - ] + script_path = self.get_launch_script_path() + new_launch_args = get_pype_execute_args( + "run", script_path, executable_path + ) + # Add workfile path if exists + workfile_path = self.data["last_workfile_path"] + if os.path.exists(workfile_path): + new_launch_args.append(workfile_path) # Append as whole list as these areguments should not be separated self.launch_context.launch_args.append(new_launch_args) @@ -38,7 +42,12 @@ def execute(self): ).format(str(remainders))) self.launch_context.launch_args.extend(remainders) - def python_executable(self): - """Should lead to python executable.""" - # TODO change in Pype 3 - return os.environ["PYPE_PYTHON_EXE"] + def get_launch_script_path(self): + """Path to launch script of photoshop implementation.""" + avalon_dir = os.path.dirname(os.path.abspath(avalon.__file__)) + script_path = os.path.join( + avalon_dir, + "harmony", + "launch_script.py" + ) + return script_path diff --git a/pype/hooks/photoshop/pre_launch_args.py b/pype/hooks/photoshop/pre_launch_args.py index 6bd40eb2e14..91c5e783259 100644 --- a/pype/hooks/photoshop/pre_launch_args.py +++ b/pype/hooks/photoshop/pre_launch_args.py @@ -1,6 +1,10 @@ import os -from pype.lib import PreLaunchHook +import avalon +from pype.lib import ( + PreLaunchHook, + get_pype_execute_args +) class PhotoshopPrelaunchHook(PreLaunchHook): @@ -12,29 +16,22 @@ class PhotoshopPrelaunchHook(PreLaunchHook): app_groups = ["photoshop"] def execute(self): - # Pop tvpaint executable - photoshop_executable = self.launch_context.launch_args.pop(0) + # Pop executable + executable_path = self.launch_context.launch_args.pop(0) # Pop rest of launch arguments - There should not be other arguments! remainders = [] while self.launch_context.launch_args: remainders.append(self.launch_context.launch_args.pop(0)) + script_path = self.get_launch_script_path() + new_launch_args = get_pype_execute_args( + "run", script_path, executable_path + ) + # Add workfile path if exists workfile_path = self.data["last_workfile_path"] - if not os.path.exists(workfile_path): - workfile_path = "" - - new_launch_args = [ - self.python_executable(), - "-c", - ( - "import avalon.photoshop;" - "avalon.photoshop.launch(\"{}\", \"{}\")" - ).format( - photoshop_executable.replace("\\", "\\\\"), - workfile_path.replace("\\", "\\\\") - ) - ] + if os.path.exists(workfile_path): + new_launch_args.append(workfile_path) # Append as whole list as these areguments should not be separated self.launch_context.launch_args.append(new_launch_args) @@ -45,7 +42,12 @@ def execute(self): ).format(str(remainders))) self.launch_context.launch_args.extend(remainders) - def python_executable(self): - """Should lead to python executable.""" - # TODO change in Pype 3 - return os.environ["PYPE_PYTHON_EXE"] + def get_launch_script_path(self): + """Path to launch script of photoshop implementation.""" + avalon_dir = os.path.dirname(os.path.abspath(avalon.__file__)) + script_path = os.path.join( + avalon_dir, + "photoshop", + "launch_script.py" + ) + return script_path From 9c0f86b5a116691c26eb42549579e3ddfee8ff58 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 15 Feb 2021 10:23:56 +0100 Subject: [PATCH 2/3] added launch script for non python hosts --- pype/scripts/non_python_host_launch.py | 107 +++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 pype/scripts/non_python_host_launch.py diff --git a/pype/scripts/non_python_host_launch.py b/pype/scripts/non_python_host_launch.py new file mode 100644 index 00000000000..1637eec7eda --- /dev/null +++ b/pype/scripts/non_python_host_launch.py @@ -0,0 +1,107 @@ +"""Script wraps launch mechanism of non python host implementations. + +Arguments passed to the script are passed to launch function in host +implementation. In all cases requires host app executable and may contain +workfile or others. +""" + +import os +import sys + +# Get current file to locate start point of sys.argv +CURRENT_FILE = os.path.abspath(__file__) + + +def show_error_messagebox(title, message, detail_message=None): + """Function will show message and process ends after closing it.""" + from Qt import QtWidgets, QtCore + from avalon import style + + app = QtWidgets.QApplication([]) + app.setStyleSheet(style.load_stylesheet()) + + msgbox = QtWidgets.QMessageBox() + msgbox.setWindowTitle(title) + msgbox.setText(message) + + if detail_message: + msgbox.setDetailedText(detail_message) + + msgbox.setWindowModality(QtCore.Qt.ApplicationModal) + msgbox.show() + + sys.exit(app.exec_()) + + +def on_invalid_args(script_not_found): + """Show to user message box saying that something went wrong. + + Tell user that arguments to launch implementation are invalid with + arguments details. + + Args: + script_not_found (bool): Use different message based on this value. + """ + + title = "Invalid arguments" + joined_args = ", ".join("\"{}\"".format(arg) for arg in sys.argv) + if script_not_found: + submsg = "Where couldn't find script path:\n\"{}\"" + else: + submsg = "Expected Host executable after script path:\n\"{}\"" + + message = "BUG: Got invalid arguments so can't launch Host application." + detail_message = "Process was launched with arguments:\n{}\n\n{}".format( + joined_args, + submsg.format(CURRENT_FILE) + ) + + show_error_messagebox(title, message, detail_message) + + +def main(argv): + # Modify current file path to find match in sys.argv which may be different + # on windows (different letter cases and slashes). + modified_current_file = CURRENT_FILE.replace("\\", "/").lower() + + # Create a copy of sys argv + sys_args = list(argv) + after_script_idx = None + # Find script path in sys.argv to know index of argv where host + # executable should be. + for idx, item in enumerate(sys_args): + if item.replace("\\", "/").lower() == modified_current_file: + after_script_idx = idx + 1 + break + + # Validate that there is at least one argument after script path + launch_args = None + if after_script_idx is not None: + launch_args = sys_args[after_script_idx:] + + host_name = os.environ["AVALON_APP"].lower() + if host_name == "photoshop": + from avalon.photoshop.lib import launch + elif host_name == "aftereffects": + from avalon.aftereffects.lib import launch + elif host_name == "harmony": + from avalon.photoshop.lib import launch + else: + title = "Unknown host name" + message = ( + "BUG: Environment variable AVALON_APP contains unknown" + " host name \"{}\"" + ).format(host_name) + show_error_messagebox(title, message) + return + + if launch_args: + # Launch host implementation + launch(*launch_args) + else: + # Show message box + on_invalid_args(after_script_idx is None) + + +if __name__ == "__main__": + main(sys.argv) From 54020eb122e07f798718ef2e62c30ce30b8e9ff8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 15 Feb 2021 10:24:22 +0100 Subject: [PATCH 3/3] replaced prelaunch hooks of non python hosts with single global hook --- pype/hooks/aftereffects/pre_launch_args.py | 54 ------------------- .../pre_non_python_host_launch.py} | 31 +++++------ pype/hooks/photoshop/pre_launch_args.py | 53 ------------------ 3 files changed, 12 insertions(+), 126 deletions(-) delete mode 100644 pype/hooks/aftereffects/pre_launch_args.py rename pype/hooks/{harmony/pre_launch_args.py => global/pre_non_python_host_launch.py} (60%) delete mode 100644 pype/hooks/photoshop/pre_launch_args.py diff --git a/pype/hooks/aftereffects/pre_launch_args.py b/pype/hooks/aftereffects/pre_launch_args.py deleted file mode 100644 index 340fa8c9dba..00000000000 --- a/pype/hooks/aftereffects/pre_launch_args.py +++ /dev/null @@ -1,54 +0,0 @@ -import os - -import avalon -from pype.lib import ( - PreLaunchHook, - get_pype_execute_args -) - - -class AfterEffectsPrelaunchHook(PreLaunchHook): - """Launch arguments preparation. - - Hook add python executable and execute python script of AfterEffects - implementation before AfterEffects executable. - """ - app_groups = ["aftereffects"] - - def execute(self): - # Pop executable - executable_path = self.launch_context.launch_args.pop(0) - - # Pop rest of launch arguments - There should not be other arguments! - remainders = [] - while self.launch_context.launch_args: - remainders.append(self.launch_context.launch_args.pop(0)) - - script_path = self.get_launch_script_path() - new_launch_args = get_pype_execute_args( - "run", script_path, executable_path - ) - # Add workfile path if exists - workfile_path = self.data["last_workfile_path"] - if os.path.exists(workfile_path): - new_launch_args.append(workfile_path) - - # Append as whole list as these arguments should not be separated - self.launch_context.launch_args.append(new_launch_args) - - if remainders: - self.log.warning(( - "There are unexpected launch arguments " - "in AfterEffects launch. {}" - ).format(str(remainders))) - self.launch_context.launch_args.extend(remainders) - - def get_launch_script_path(self): - """Path to launch script of photoshop implementation.""" - avalon_dir = os.path.dirname(os.path.abspath(avalon.__file__)) - script_path = os.path.join( - avalon_dir, - "AfterEffects", - "launch_script.py" - ) - return script_path diff --git a/pype/hooks/harmony/pre_launch_args.py b/pype/hooks/global/pre_non_python_host_launch.py similarity index 60% rename from pype/hooks/harmony/pre_launch_args.py rename to pype/hooks/global/pre_non_python_host_launch.py index 619c91a5224..87b6cbad01b 100644 --- a/pype/hooks/harmony/pre_launch_args.py +++ b/pype/hooks/global/pre_non_python_host_launch.py @@ -1,19 +1,20 @@ import os -import avalon from pype.lib import ( PreLaunchHook, get_pype_execute_args ) +import pype.PACKAGE_DIR -class HarmonyPrelaunchHook(PreLaunchHook): +class NonPythonHostHook(PreLaunchHook): """Launch arguments preparation. - Hook add python executable and execute python script of harmony - implementation before harmony executable. + Non python host implementation do not launch host directly but use + python script which launch the host. For these cases it is necessary to + prepend python (or pype) executable and script path before application's. """ - app_groups = ["harmony"] + app_groups = ["harmony", "photoshop", "aftereffects"] def execute(self): # Pop executable @@ -24,7 +25,12 @@ def execute(self): while self.launch_context.launch_args: remainders.append(self.launch_context.launch_args.pop(0)) - script_path = self.get_launch_script_path() + script_path = os.path.join( + pype.PACKAGE_DIR, + "scripts", + "non_python_host_launch.py" + ) + new_launch_args = get_pype_execute_args( "run", script_path, executable_path ) @@ -37,17 +43,4 @@ def execute(self): self.launch_context.launch_args.append(new_launch_args) if remainders: - self.log.warning(( - "There are unexpected launch arguments in Harmony launch. {}" - ).format(str(remainders))) self.launch_context.launch_args.extend(remainders) - - def get_launch_script_path(self): - """Path to launch script of photoshop implementation.""" - avalon_dir = os.path.dirname(os.path.abspath(avalon.__file__)) - script_path = os.path.join( - avalon_dir, - "harmony", - "launch_script.py" - ) - return script_path diff --git a/pype/hooks/photoshop/pre_launch_args.py b/pype/hooks/photoshop/pre_launch_args.py deleted file mode 100644 index 91c5e783259..00000000000 --- a/pype/hooks/photoshop/pre_launch_args.py +++ /dev/null @@ -1,53 +0,0 @@ -import os - -import avalon -from pype.lib import ( - PreLaunchHook, - get_pype_execute_args -) - - -class PhotoshopPrelaunchHook(PreLaunchHook): - """Launch arguments preparation. - - Hook add python executable and execute python script of photoshop - implementation before photoshop executable. - """ - app_groups = ["photoshop"] - - def execute(self): - # Pop executable - executable_path = self.launch_context.launch_args.pop(0) - - # Pop rest of launch arguments - There should not be other arguments! - remainders = [] - while self.launch_context.launch_args: - remainders.append(self.launch_context.launch_args.pop(0)) - - script_path = self.get_launch_script_path() - new_launch_args = get_pype_execute_args( - "run", script_path, executable_path - ) - # Add workfile path if exists - workfile_path = self.data["last_workfile_path"] - if os.path.exists(workfile_path): - new_launch_args.append(workfile_path) - - # Append as whole list as these areguments should not be separated - self.launch_context.launch_args.append(new_launch_args) - - if remainders: - self.log.warning(( - "There are unexpected launch arguments in Photoshop launch. {}" - ).format(str(remainders))) - self.launch_context.launch_args.extend(remainders) - - def get_launch_script_path(self): - """Path to launch script of photoshop implementation.""" - avalon_dir = os.path.dirname(os.path.abspath(avalon.__file__)) - script_path = os.path.join( - avalon_dir, - "photoshop", - "launch_script.py" - ) - return script_path