mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-25 05:14:40 +01:00
Merge branch 'develop' into PS_to_3.0_structure
This commit is contained in:
commit
8ddaa5bbd4
12 changed files with 218 additions and 170 deletions
|
|
@ -1,52 +0,0 @@
|
|||
import os
|
||||
|
||||
from pype.lib import PreLaunchHook
|
||||
|
||||
|
||||
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 tvpaint executable
|
||||
aftereffects_executable = 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))
|
||||
|
||||
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("\\", "\\\\")
|
||||
)
|
||||
]
|
||||
|
||||
# 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 python_executable(self):
|
||||
"""Should lead to python executable."""
|
||||
# TODO change in Pype 3
|
||||
return os.environ["PYPE_PYTHON_EXE"]
|
||||
46
pype/hooks/global/pre_non_python_host_launch.py
Normal file
46
pype/hooks/global/pre_non_python_host_launch.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import os
|
||||
|
||||
from pype.lib import (
|
||||
PreLaunchHook,
|
||||
get_pype_execute_args
|
||||
)
|
||||
import pype.PACKAGE_DIR
|
||||
|
||||
|
||||
class NonPythonHostHook(PreLaunchHook):
|
||||
"""Launch arguments preparation.
|
||||
|
||||
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", "photoshop", "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 = os.path.join(
|
||||
pype.PACKAGE_DIR,
|
||||
"scripts",
|
||||
"non_python_host_launch.py"
|
||||
)
|
||||
|
||||
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.launch_context.launch_args.extend(remainders)
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
import os
|
||||
|
||||
from pype.lib import PreLaunchHook
|
||||
|
||||
|
||||
class HarmonyPrelaunchHook(PreLaunchHook):
|
||||
"""Launch arguments preparation.
|
||||
|
||||
Hook add python executable and execute python script of harmony
|
||||
implementation before harmony executable.
|
||||
"""
|
||||
app_groups = ["harmony"]
|
||||
|
||||
def execute(self):
|
||||
# Pop tvpaint executable
|
||||
harmony_executable = 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("\\", "\\\\"))
|
||||
]
|
||||
|
||||
# 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 Harmony launch. {}"
|
||||
).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"]
|
||||
|
|
@ -34,11 +34,10 @@ class CelactionPrelaunchHook(PreLaunchHook):
|
|||
"Software\\CelAction\\CelAction2D\\User Settings", 0,
|
||||
winreg.KEY_ALL_ACCESS)
|
||||
|
||||
# TODO: change to pype executable
|
||||
pype_root_path = os.getenv("PYPE_SETUP_PATH")
|
||||
path = os.path.join(pype_root_path, "pype.bat")
|
||||
# TODO: this will need to be checked more thoroughly
|
||||
pype_exe = os.getenv("PYPE_EXECUTABLE")
|
||||
|
||||
winreg.SetValueEx(hKey, "SubmitAppTitle", 0, winreg.REG_SZ, path)
|
||||
winreg.SetValueEx(hKey, "SubmitAppTitle", 0, winreg.REG_SZ, pype_exe)
|
||||
|
||||
parameters = [
|
||||
"launch",
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
import os
|
||||
|
||||
from pype.lib import PreLaunchHook
|
||||
|
||||
|
||||
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 tvpaint executable
|
||||
photoshop_executable = 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))
|
||||
|
||||
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("\\", "\\\\")
|
||||
)
|
||||
]
|
||||
|
||||
# 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 python_executable(self):
|
||||
"""Should lead to python executable."""
|
||||
# TODO change in Pype 3
|
||||
return os.environ["PYPE_PYTHON_EXE"]
|
||||
|
|
@ -89,15 +89,15 @@ class CollectContextDataSAPublish(pyblish.api.ContextPlugin):
|
|||
files = [files]
|
||||
|
||||
self.log.debug(f"_ files: {files}")
|
||||
for index, f in enumerate(files):
|
||||
for index, _file in enumerate(files):
|
||||
index += 1
|
||||
# copy dictionaries
|
||||
in_data_copy = copy.deepcopy(in_data_copy)
|
||||
repr_new = copy.deepcopy(repr)
|
||||
new_repre = copy.deepcopy(repre)
|
||||
|
||||
repr_new["files"] = f
|
||||
repr_new["name"] = ext
|
||||
in_data_copy["representations"] = [repr_new]
|
||||
new_repre["files"] = _file
|
||||
new_repre["name"] = ext
|
||||
in_data_copy["representations"] = [new_repre]
|
||||
|
||||
# create subset Name
|
||||
new_subset = f"{ext}{index}{subset}"
|
||||
|
|
|
|||
|
|
@ -52,7 +52,11 @@ class ExtractBGForComp(pype.api.Extractor):
|
|||
|
||||
for repre in tuple(repres):
|
||||
# Skip all files without .psd extension
|
||||
if repre["ext"] != ".psd":
|
||||
repre_ext = repre["ext"].lower()
|
||||
if repre_ext.startswith("."):
|
||||
repre_ext = repre_ext[1:]
|
||||
|
||||
if repre_ext != "psd":
|
||||
continue
|
||||
|
||||
# Prepare publish dir for transfers
|
||||
|
|
|
|||
|
|
@ -61,7 +61,11 @@ class ExtractBGMainGroups(pype.api.Extractor):
|
|||
|
||||
for repre in tuple(repres):
|
||||
# Skip all files without .psd extension
|
||||
if repre["ext"] != ".psd":
|
||||
repre_ext = repre["ext"].lower()
|
||||
if repre_ext.startswith("."):
|
||||
repre_ext = repre_ext[1:]
|
||||
|
||||
if repre_ext != "psd":
|
||||
continue
|
||||
|
||||
# Prepare json filepath where extracted metadata are stored
|
||||
|
|
@ -101,7 +105,9 @@ class ExtractBGMainGroups(pype.api.Extractor):
|
|||
"__schema_version__": 1,
|
||||
"children": []
|
||||
}
|
||||
transfers = []
|
||||
output_ext = ".png"
|
||||
|
||||
to_export = []
|
||||
for layer_idx, layer in enumerate(psd_object):
|
||||
layer_name = layer.name.replace(" ", "_")
|
||||
if (
|
||||
|
|
@ -117,13 +123,42 @@ class ExtractBGMainGroups(pype.api.Extractor):
|
|||
).format(layer.name))
|
||||
continue
|
||||
|
||||
filename = "{:0>2}_{}.png".format(layer_idx, layer_name)
|
||||
layer_data = {
|
||||
filebase = "{:0>2}_{}".format(layer_idx, layer_name)
|
||||
if layer_name.lower() == "anim":
|
||||
if not layer.is_group:
|
||||
self.log.warning("ANIM layer is not a group layer.")
|
||||
continue
|
||||
|
||||
children = []
|
||||
for anim_idx, anim_layer in enumerate(layer):
|
||||
anim_layer_name = anim_layer.name.replace(" ", "_")
|
||||
filename = "{}_{:0>2}_{}{}".format(
|
||||
filebase, anim_idx, anim_layer_name, output_ext
|
||||
)
|
||||
children.append({
|
||||
"index": anim_idx,
|
||||
"name": anim_layer.name,
|
||||
"filename": filename
|
||||
})
|
||||
to_export.append((anim_layer, filename))
|
||||
|
||||
json_data["children"].append({
|
||||
"index": layer_idx,
|
||||
"name": layer.name,
|
||||
"children": children
|
||||
})
|
||||
continue
|
||||
|
||||
filename = filebase + output_ext
|
||||
json_data["children"].append({
|
||||
"index": layer_idx,
|
||||
"name": layer.name,
|
||||
"filename": filename
|
||||
}
|
||||
})
|
||||
to_export.append((layer, filename))
|
||||
|
||||
transfers = []
|
||||
for layer, filename in to_export:
|
||||
output_filepath = os.path.join(output_dir, filename)
|
||||
dst_filepath = os.path.join(publish_dir, filename)
|
||||
transfers.append((output_filepath, dst_filepath))
|
||||
|
|
@ -131,8 +166,6 @@ class ExtractBGMainGroups(pype.api.Extractor):
|
|||
pil_object = layer.composite(viewport=psd_object.viewbox)
|
||||
pil_object.save(output_filepath, "PNG")
|
||||
|
||||
json_data["children"].append(layer_data)
|
||||
|
||||
return json_data, transfers
|
||||
|
||||
def redo_global_plugins(self, instance):
|
||||
|
|
|
|||
|
|
@ -46,7 +46,11 @@ class ExtractImagesFromPSD(pype.api.Extractor):
|
|||
|
||||
for repre in tuple(repres):
|
||||
# Skip all files without .psd extension
|
||||
if repre["ext"] != ".psd":
|
||||
repre_ext = repre["ext"].lower()
|
||||
if repre_ext.startswith("."):
|
||||
repre_ext = repre_ext[1:]
|
||||
|
||||
if repre_ext != "psd":
|
||||
continue
|
||||
|
||||
# TODO add check of list of "files" value
|
||||
|
|
|
|||
107
pype/scripts/non_python_host_launch.py
Normal file
107
pype/scripts/non_python_host_launch.py
Normal file
|
|
@ -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)
|
||||
|
|
@ -71,7 +71,9 @@ class SchemaTemplateMissingKeys(Exception):
|
|||
self.missing_keys = missing_keys
|
||||
self.required_keys = required_keys
|
||||
if template_name:
|
||||
msg = f"Schema template \"{template_name}\" require more keys.\n"
|
||||
msg = "Schema template \"{}\" require more keys.\n".format(
|
||||
template_name
|
||||
)
|
||||
else:
|
||||
msg = ""
|
||||
msg += "Required keys: {}\nMissing keys: {}".format(
|
||||
|
|
@ -82,5 +84,5 @@ class SchemaTemplateMissingKeys(Exception):
|
|||
|
||||
def join_keys(self, keys):
|
||||
return ", ".join([
|
||||
f"\"{key}\"" for key in keys
|
||||
"\"{}\"".format(key) for key in keys
|
||||
])
|
||||
|
|
|
|||
|
|
@ -252,9 +252,9 @@ def gui_schema(subfolder, main_schema_name):
|
|||
try:
|
||||
schema_data = json.load(json_stream)
|
||||
except Exception as exc:
|
||||
raise Exception((
|
||||
f"Unable to parse JSON file {filepath}\n{exc}"
|
||||
)) from exc
|
||||
raise ValueError((
|
||||
"Unable to parse JSON file {}\n{}"
|
||||
).format(filepath, str(exc)))
|
||||
if isinstance(schema_data, list):
|
||||
loaded_schema_templates[basename] = schema_data
|
||||
else:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue