Merge branch 'develop' into PS_to_3.0_structure

This commit is contained in:
Milan Kolar 2021-02-15 11:49:56 +01:00
commit 8ddaa5bbd4
12 changed files with 218 additions and 170 deletions

View file

@ -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"]

View 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)

View file

@ -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"]

View file

@ -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",

View file

@ -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"]

View file

@ -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}"

View file

@ -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

View file

@ -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):

View file

@ -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

View 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)

View file

@ -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
])

View file

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