Skip to content

Commit

Permalink
Merge pull request #107 from BigRoy/enhancement/AY-6326_load_filepath…
Browse files Browse the repository at this point in the history
…_udim

Load filepath to node: Use <UDIM> token
  • Loading branch information
BigRoy committed Sep 24, 2024
2 parents c3ab366 + 083fcf7 commit aec3535
Showing 1 changed file with 49 additions and 22 deletions.
71 changes: 49 additions & 22 deletions client/ayon_houdini/plugins/load/load_filepath.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,35 @@
import re
import hou

from ayon_core.pipeline import Anatomy
from ayon_core.lib import StringTemplate
from ayon_houdini.api import (
pipeline,
plugin
)


def remove_format_spec(template: str, key: str) -> str:
"""Remove format specifier from a format token in formatting string.
For example, change `{frame:0>4d}` into `{frame}`
Examples:
>>> remove_format_spec("{frame:0>4d}", "frame")
'{frame}'
>>> remove_format_spec("{digit:04d}/{frame:0>4d}", "frame")
'{digit:04d}/{udim}_{frame}'
>>> remove_format_spec("{a: >4}/{aa: >4}", "a")
'{a}/{aa: >4}'
"""
# Find all {key:foobar} and remove the `:foobar`
# Pattern will be like `({key):[^}]+(})` where we use the captured groups
# to keep those parts in the resulting string
pattern = f"({{{key}):[^}}]+(}})"
return re.sub(pattern, r"\1\2", template)


class FilePathLoader(plugin.HoudiniLoader):
"""Load a managed filepath to a null node.
Expand Down Expand Up @@ -42,10 +65,7 @@ def load(self, context, name=None, namespace=None, data=None):
node.destroy()

# Add filepath attribute, set value as default value
filepath = self.format_path(
path=self.filepath_from_context(context),
representation=context["representation"]
)
filepath = self.filepath_from_context(context)
parm_template_group = container.parmTemplateGroup()
attr_folder = hou.FolderParmTemplate("attributes_folder", "Attributes")
parm = hou.StringParmTemplate(name="filepath",
Expand Down Expand Up @@ -85,21 +105,18 @@ def update(self, container, context):

# Update the file path
representation_entity = context["representation"]
file_path = self.format_path(
path=self.filepath_from_context(context),
representation=representation_entity
)
filepath = self.filepath_from_context(context)

node = container["node"]
node.setParms({
"filepath": file_path,
"filepath": filepath,
"representation": str(representation_entity["id"])
})

# Update the parameter default value (cosmetics)
parm_template_group = node.parmTemplateGroup()
parm = parm_template_group.find("filepath")
parm.setDefaultValue((file_path,))
parm.setDefaultValue((filepath,))
parm_template_group.replace(parm_template_group.find("filepath"),
parm)
node.setParmTemplateGroup(parm_template_group)
Expand All @@ -112,19 +129,29 @@ def remove(self, container):
node = container["node"]
node.destroy()

@staticmethod
def format_path(path: str, representation: dict) -> str:
"""Format file path for sequence with $F."""
if not os.path.exists(path):
raise RuntimeError("Path does not exist: %s" % path)

def filepath_from_context(self, context: dict) -> str:
"""Format file path for sequence with $F or <UDIM>."""
# The path is either a single file or sequence in a folder.
# Format frame as $F and udim as <UDIM>
representation = context["representation"]
frame = representation["context"].get("frame")
if frame is not None:
# Substitute frame number in sequence with $F with padding
ext = representation.get("ext", representation["name"])
token = "$F{}".format(len(frame)) # e.g. $F4
pattern = r"\.(\d+)\.{ext}$".format(ext=re.escape(ext))
path = re.sub(pattern, ".{}.{}".format(token, ext), path)
udim = representation["context"].get("udim")
if frame is not None or udim is not None:
template: str = representation["attrib"]["template"]
repre_context: dict = representation["context"]
if udim is not None:
repre_context["udim"] = "<UDIM>"
template = remove_format_spec(template, "udim")
if frame is not None:
# Substitute frame number in sequence with $F with padding
repre_context["frame"] = "$F{}".format(len(frame)) # e.g. $F4
template = remove_format_spec(template, "frame")

project_name: str = repre_context["project"]["name"]
anatomy = Anatomy(project_name, project_entity=context["project"])
repre_context["root"] = anatomy.roots
path = StringTemplate(template).format(repre_context)
else:
path = super().filepath_from_context(context)

return os.path.normpath(path).replace("\\", "/")

0 comments on commit aec3535

Please sign in to comment.