Skip to content

Commit

Permalink
Merge branch 'develop' into bugfix/#895_fix_otio_subset_resources_img…
Browse files Browse the repository at this point in the history
…_sequence
  • Loading branch information
jakubjezek001 authored Oct 2, 2024
2 parents 1072fc9 + ddd1883 commit 029cbe4
Show file tree
Hide file tree
Showing 14 changed files with 319 additions and 76 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/release_trigger.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: 🚀 Release Trigger

on:
workflow_dispatch:

jobs:
call-release-trigger:
uses: ynput/ops-repo-automation/.github/workflows/release_trigger.yml@main
secrets:
token: ${{ secrets.YNPUT_BOT_TOKEN }}
email: ${{ secrets.CI_EMAIL }}
user: ${{ secrets.CI_USER }}
3 changes: 2 additions & 1 deletion client/ayon_core/hooks/pre_ocio_hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class OCIOEnvHook(PreLaunchHook):
"nuke",
"hiero",
"resolve",
"openrv"
"openrv",
"cinema4d"
}
launch_types = set()

Expand Down
5 changes: 4 additions & 1 deletion client/ayon_core/lib/path_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,10 @@ def collect_frames(files):
dict: {'/folder/product_v001.0001.png': '0001', ....}
"""

patterns = [clique.PATTERNS["frames"]]
# clique.PATTERNS["frames"] supports only `.1001.exr` not `_1001.exr` so
# we use a customized pattern.
pattern = "[_.](?P<index>(?P<padding>0*)\\d+)\\.\\D+\\d?$"
patterns = [pattern]
collections, remainder = clique.assemble(
files, minimum_items=1, patterns=patterns)

Expand Down
2 changes: 0 additions & 2 deletions client/ayon_core/pipeline/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
AVALON_INSTANCE_ID,
AYON_CONTAINER_ID,
AYON_INSTANCE_ID,
HOST_WORKFILE_EXTENSIONS,
)

from .anatomy import Anatomy
Expand Down Expand Up @@ -114,7 +113,6 @@
"AVALON_INSTANCE_ID",
"AYON_CONTAINER_ID",
"AYON_INSTANCE_ID",
"HOST_WORKFILE_EXTENSIONS",

# --- Anatomy ---
"Anatomy",
Expand Down
76 changes: 56 additions & 20 deletions client/ayon_core/pipeline/colorspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,34 @@ def get_ocio_config_views(config_path):
)


def _get_config_path_from_profile_data(
profile, profile_type, template_data
):
"""Get config path from profile data.
Args:
profile (dict[str, Any]): Profile data.
profile_type (str): Profile type.
template_data (dict[str, Any]): Template data.
Returns:
dict[str, str]: Config data with path and template.
"""
template = profile[profile_type]
result = StringTemplate.format_strict_template(
template, template_data
)
normalized_path = str(result.normalized())
if not os.path.exists(normalized_path):
log.warning(f"Path was not found '{normalized_path}'.")
return None

return {
"path": normalized_path,
"template": template
}


def _get_global_config_data(
project_name,
host_name,
Expand All @@ -717,7 +745,7 @@ def _get_global_config_data(
2. Custom path to ocio config.
3. Path to 'ocioconfig' representation on product. Name of product can be
defined in settings. Product name can be regex but exact match is
always preferred.
always preferred. Fallback can be defined in case no product is found.
None is returned when no profile is found, when path
Expand Down Expand Up @@ -755,30 +783,36 @@ def _get_global_config_data(

profile_type = profile["type"]
if profile_type in ("builtin_path", "custom_path"):
template = profile[profile_type]
result = StringTemplate.format_strict_template(
template, template_data
)
normalized_path = str(result.normalized())
if not os.path.exists(normalized_path):
log.warning(f"Path was not found '{normalized_path}'.")
return None

return {
"path": normalized_path,
"template": template
}
return _get_config_path_from_profile_data(
profile, profile_type, template_data)

# TODO decide if this is the right name for representation
repre_name = "ocioconfig"

published_product_data = profile["published_product"]
product_name = published_product_data["product_name"]
fallback_data = published_product_data["fallback"]

if product_name == "":
log.error(
"Colorspace OCIO config path cannot be set. "
"Profile is set to published product but `Product name` is empty."
)
return None

folder_info = template_data.get("folder")
if not folder_info:
log.warning("Folder info is missing.")
return None

log.info("Using fallback data for ocio config path.")
# in case no product was found we need to use fallback
fallback_type = fallback_data["fallback_type"]
return _get_config_path_from_profile_data(
fallback_data, fallback_type, template_data
)

folder_path = folder_info["path"]

product_name = profile["product_name"]
if folder_id is None:
folder_entity = ayon_api.get_folder_by_path(
project_name, folder_path, fields={"id"}
Expand All @@ -797,12 +831,13 @@ def _get_global_config_data(
fields={"id", "name"}
)
}

if not product_entities_by_name:
log.debug(
f"No product entities were found for folder '{folder_path}' with"
f" product name filter '{product_name}'."
# in case no product was found we need to use fallback
fallback_type = fallback_data["type"]
return _get_config_path_from_profile_data(
fallback_data, fallback_type, template_data
)
return None

# Try to use exact match first, otherwise use first available product
product_entity = product_entities_by_name.get(product_name)
Expand Down Expand Up @@ -837,6 +872,7 @@ def _get_global_config_data(

path = get_representation_path_with_anatomy(repre_entity, anatomy)
template = repre_entity["attrib"]["template"]

return {
"path": path,
"template": template,
Expand Down
17 changes: 0 additions & 17 deletions client/ayon_core/pipeline/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,3 @@
# Backwards compatibility
AVALON_CONTAINER_ID = "pyblish.avalon.container"
AVALON_INSTANCE_ID = "pyblish.avalon.instance"

# TODO get extensions from host implementations
HOST_WORKFILE_EXTENSIONS = {
"blender": [".blend"],
"celaction": [".scn"],
"tvpaint": [".tvpp"],
"fusion": [".comp"],
"harmony": [".zip"],
"houdini": [".hip", ".hiplc", ".hipnc"],
"maya": [".ma", ".mb"],
"nuke": [".nk"],
"hiero": [".hrox"],
"photoshop": [".psd", ".psb"],
"premiere": [".prproj"],
"resolve": [".drp"],
"aftereffects": [".aep"]
}
18 changes: 17 additions & 1 deletion client/ayon_core/plugins/load/delivery.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,11 @@ def deliver(self):
self.log
]

# TODO: This will currently incorrectly detect 'resources'
# that are published along with the publish, because those should
# not adhere to the template directly but are ingested in a
# customized way. For example, maya look textures or any publish
# that directly adds files into `instance.data["transfers"]`
src_paths = []
for repre_file in repre["files"]:
src_path = self.anatomy.fill_root(repre_file["path"])
Expand Down Expand Up @@ -261,7 +266,18 @@ def deliver(self):
frame = dst_frame

if frame is not None:
anatomy_data["frame"] = frame
if repre["context"].get("frame"):
anatomy_data["frame"] = frame
elif repre["context"].get("udim"):
anatomy_data["udim"] = frame
else:
# Fallback
self.log.warning(
"Representation context has no frame or udim"
" data. Supplying sequence frame to '{frame}'"
" formatting data."
)
anatomy_data["frame"] = frame
new_report_items, uploaded = deliver_single_file(*args)
report_items.update(new_report_items)
self._update_progress(uploaded)
Expand Down
19 changes: 14 additions & 5 deletions client/ayon_core/plugins/publish/extract_color_transcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,22 @@ def process(self, instance):
transcoding_type = output_def["transcoding_type"]

target_colorspace = view = display = None
# NOTE: we use colorspace_data as the fallback values for
# the target colorspace.
if transcoding_type == "colorspace":
# TODO: Should we fallback to the colorspace
# (which used as source above) ?
# or should we compute the target colorspace from
# current view and display ?
target_colorspace = (output_def["colorspace"] or
colorspace_data.get("colorspace"))
else:
view = output_def["view"] or colorspace_data.get("view")
display = (output_def["display"] or
colorspace_data.get("display"))
elif transcoding_type == "display_view":
display_view = output_def["display_view"]
view = display_view["view"] or colorspace_data.get("view")
display = (
display_view["display"]
or colorspace_data.get("display")
)

# both could be already collected by DCC,
# but could be overwritten when transcoding
Expand Down Expand Up @@ -192,7 +201,7 @@ def process(self, instance):
new_repre["files"] = new_repre["files"][0]

# If the source representation has "review" tag, but its not
# part of the output defintion tags, then both the
# part of the output definition tags, then both the
# representations will be transcoded in ExtractReview and
# their outputs will clash in integration.
if "review" in repre.get("tags", []):
Expand Down
7 changes: 5 additions & 2 deletions client/ayon_core/plugins/publish/integrate.py
Original file line number Diff line number Diff line change
Expand Up @@ -509,8 +509,11 @@ def _validate_repre_files(self, files, is_sequence_representation):
if not is_sequence_representation:
files = [files]

if any(os.path.isabs(fname) for fname in files):
raise KnownPublishError("Given file names contain full paths")
for fname in files:
if os.path.isabs(fname):
raise KnownPublishError(
f"Representation file names contains full paths: {fname}"
)

if not is_sequence_representation:
return
Expand Down
3 changes: 2 additions & 1 deletion client/ayon_core/plugins/publish/validate_file_saved.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ class ValidateCurrentSaveFile(pyblish.api.ContextPlugin):

label = "Validate File Saved"
order = pyblish.api.ValidatorOrder - 0.1
hosts = ["fusion", "houdini", "max", "maya", "nuke", "substancepainter"]
hosts = ["fusion", "houdini", "max", "maya", "nuke", "substancepainter",
"cinema4d"]
actions = [SaveByVersionUpAction, ShowWorkfilesAction]

def process(self, context):
Expand Down
5 changes: 4 additions & 1 deletion client/ayon_core/tools/publisher/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,10 +439,13 @@ def set_comment(self, comment):
def make_sure_is_visible(self):
if self._window_is_visible:
self.setWindowState(QtCore.Qt.WindowActive)

else:
self.show()

self.raise_()
self.activateWindow()
self.showNormal()

def showEvent(self, event):
self._window_is_visible = True
super().showEvent(event)
Expand Down
61 changes: 59 additions & 2 deletions server/settings/conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,29 @@
from .publish_plugins import DEFAULT_PUBLISH_VALUES


def _convert_imageio_configs_0_4_5(overrides):
"""Imageio config settings did change to profiles since 0.4.5."""
imageio_overrides = overrides.get("imageio") or {}

# make sure settings are already converted to profiles
ocio_config_profiles = imageio_overrides.get("ocio_config_profiles")
if not ocio_config_profiles:
return

for profile in ocio_config_profiles:
if profile.get("type") != "product_name":
continue

profile["type"] = "published_product"
profile["published_product"] = {
"product_name": profile.pop("product_name"),
"fallback": {
"type": "builtin_path",
"builtin_path": "{BUILTIN_OCIO_ROOT}/aces_1.2/config.ocio",
},
}


def _convert_imageio_configs_0_3_1(overrides):
"""Imageio config settings did change to profiles since 0.3.1. ."""
imageio_overrides = overrides.get("imageio") or {}
Expand Down Expand Up @@ -71,16 +94,50 @@ def _convert_validate_version_0_3_3(publish_overrides):
validate_version["plugin_state_profiles"] = [profile]


def _conver_publish_plugins(overrides):
def _convert_oiio_transcode_0_4_5(publish_overrides):
"""ExtractOIIOTranscode plugin changed in 0.4.5."""
if "ExtractOIIOTranscode" not in publish_overrides:
return

transcode_profiles = publish_overrides["ExtractOIIOTranscode"].get(
"profiles")
if not transcode_profiles:
return

for profile in transcode_profiles:
outputs = profile.get("outputs")
if outputs is None:
return

for output in outputs:
# Already new settings
if "display_view" in output:
break

# Fix 'display' -> 'display_view' in 'transcoding_type'
transcode_type = output.get("transcoding_type")
if transcode_type == "display":
output["transcoding_type"] = "display_view"

# Convert 'display' and 'view' to new values
output["display_view"] = {
"display": output.pop("display", ""),
"view": output.pop("view", ""),
}


def _convert_publish_plugins(overrides):
if "publish" not in overrides:
return
_convert_validate_version_0_3_3(overrides["publish"])
_convert_oiio_transcode_0_4_5(overrides["publish"])


def convert_settings_overrides(
source_version: str,
overrides: dict[str, Any],
) -> dict[str, Any]:
_convert_imageio_configs_0_3_1(overrides)
_conver_publish_plugins(overrides)
_convert_imageio_configs_0_4_5(overrides)
_convert_publish_plugins(overrides)
return overrides
Loading

0 comments on commit 029cbe4

Please sign in to comment.