Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert addon for new ayon core #2

Merged
merged 8 commits into from
Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions client/ayon_openrv/addon.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os
from openpype.modules import AYONAddon
from openpype.modules.interfaces import IHostAddon

from ayon_core.addon import AYONAddon, IHostAddon

OPENRV_ROOT_DIR = os.path.dirname(os.path.abspath(__file__))

Expand All @@ -16,7 +16,7 @@ def add_implementation_envs(self, env, app):
"""Modify environments to contain all required for implementation."""
# Set default environments if are not set via settings
defaults = {
"OPENPYPE_LOG_NO_COLORS": "True"
"AYON_LOG_NO_COLORS": "True"
}
for key, value in defaults.items():
if not env.get(key):
Expand Down
20 changes: 10 additions & 10 deletions client/ayon_openrv/api/commands.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import logging

import rv
from openpype.pipeline.context_tools import get_current_project_asset
from ayon_core.pipeline.context_tools import get_current_folder_entity

log = logging.getLogger(__name__)


def reset_frame_range():
""" Set timeline frame range.
"""
asset_doc = get_current_project_asset()
asset_name = asset_doc["name"]
asset_data = asset_doc["data"]
folder_entity = get_current_folder_entity(fields={"path", "attrib"})
folder_path = folder_entity["path"]
folder_attribs = folder_entity["attrib"]
Comment on lines +12 to +14
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since AYON core refactoring many other DCCs swapped this out with using the attributes from the Task Entity instead. Should this as well? get_current_task_entity?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted, but then I was like: That should be different PR, it can be in changelog.


frame_start = asset_data.get("frameStart")
frame_end = asset_data.get("frameEnd")
frame_start = folder_attribs.get("frameStart")
frame_end = folder_attribs.get("frameEnd")

if frame_start is None or frame_end is None:
log.warning("No edit information found for {}".format(asset_name))
log.warning("No edit information found for {}".format(folder_path))
Comment on lines 19 to +20
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I know folder entities in AYON always have attrib.frameStart and attrib.frameEnd. When it does not that would be considered a bug in the backend? Right? If that's ensured to exist always on a folder then maybe this is None check can be removed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do with task entity PR :)

return

rv.commands.setFrameStart(frame_start)
Expand All @@ -28,7 +28,7 @@ def reset_frame_range():
def set_session_fps():
""" Set session fps.
"""
asset_doc = get_current_project_asset()
asset_data = asset_doc["data"]
fps = float(asset_data.get("fps", 25))
folder_entity = get_current_folder_entity(fields={"attrib"})

fps = float(folder_entity["attrib"].get("fps", 25))
rv.commands.setFPS(fps)
7 changes: 4 additions & 3 deletions client/ayon_openrv/api/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
import pyblish
import rv

from openpype.host import HostBase, ILoadHost, IWorkfileHost, IPublishHost
from ayon_openrv import OPENRV_ROOT_DIR
from openpype.pipeline import (

from ayon_core.host import HostBase, ILoadHost, IWorkfileHost, IPublishHost
from ayon_core.pipeline import (
register_loader_plugin_path,
register_inventory_action_path,
register_creator_plugin_path,
Expand Down Expand Up @@ -47,7 +48,7 @@ def save_workfile(self, filepath=None):
return rv.commands.saveSession(filepath)

def work_root(self, session):
work_dir = session.get("AVALON_WORKDIR")
work_dir = session.get("AYON_WORKDIR")
scene_dir = session.get("AVALON_SCENEDIR")
if scene_dir:
return os.path.join(work_dir, scene_dir)
Expand Down
2 changes: 1 addition & 1 deletion client/ayon_openrv/hooks/pre_ftrackdata.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import json
import tempfile

from openpype.lib import PreLaunchHook
from ayon_applications import PreLaunchHook


class PreFtrackData(PreLaunchHook):
Expand Down
4 changes: 2 additions & 2 deletions client/ayon_openrv/hooks/pre_setup_openrv.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import tempfile
from pathlib import Path

from openpype.lib import PreLaunchHook
from ayon_openrv import OPENRV_ROOT_DIR
from openpype.lib.execute import run_subprocess
from ayon_applications import PreLaunchHook
from ayon_core.lib.execute import run_subprocess


class PreSetupOpenRV(PreLaunchHook):
Expand Down
82 changes: 54 additions & 28 deletions client/ayon_openrv/plugins/create/create_workfile.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import qtawesome
import ayon_api

from ayon_openrv.api.pipeline import (
read, imprint
)
from openpype.client import get_asset_by_name
from openpype.pipeline import (
from ayon_core.pipeline import (
AutoCreator,
CreatedInstance,
legacy_io
)


class OpenRVWorkfileCreator(AutoCreator):
identifier = "workfile"
family = "workfile"
product_type = "workfile"
label = "Workfile"

default_variant = "Main"
Expand All @@ -30,9 +29,12 @@ def collect_instances(self):
if not data:
return

product_name = data.get("productName")
if product_name is None:
product_name = data.get("subset")
instance = CreatedInstance(
family=self.family,
subset_name=data["subset"],
product_type=self.product_type,
product_name=product_name,
data=data,
creator=self
)
Expand All @@ -47,51 +49,75 @@ def update_instances(self, update_list):
prefix=self.data_store_prefix)

def create(self, options=None):

existing_instance = None
for instance in self.create_context.instances:
if instance.family == self.family:
if instance.product_type == self.product_type:
existing_instance = instance
break

project_name = legacy_io.Session["AVALON_PROJECT"]
asset_name = legacy_io.Session["AVALON_ASSET"]
task_name = legacy_io.Session["AVALON_TASK"]
host_name = legacy_io.Session["AVALON_APP"]
context = self.create_context
project_name = context.get_current_project_name()
folder_path = context.get_current_folder_path()
task_name = context.get_current_task_name()
host_name = context.host_name

existing_folder_path = None
if existing_instance is not None:
existing_folder_path = existing_instance.get("folderPath")

if existing_instance is None:
asset_doc = get_asset_by_name(project_name, asset_name)
subset_name = self.get_subset_name(
self.default_variant, task_name, asset_doc,
project_name, host_name
folder_entity = ayon_api.get_folder_by_path(
project_name, folder_path
)
task_entity = ayon_api.get_task_by_name(
project_name, folder_entity["id"], task_name
)
product_name = self.get_product_name(
project_name,
folder_entity,
task_entity,
self.default_variant,
host_name,
)
data = {
"asset": asset_name,
"folderPath": folder_path,
"task": task_name,
"variant": self.default_variant
"variant": self.default_variant,
}
data.update(self.get_dynamic_data(
self.default_variant, task_name, asset_doc,
project_name, host_name, None
project_name,
folder_entity,
task_entity,
self.default_variant,
host_name,
None,
))

new_instance = CreatedInstance(
self.family, subset_name, data, self
self.product_type, product_name, data, self
)
self._add_instance_to_context(new_instance)

elif (
existing_instance["folderPath"] != asset_name
existing_folder_path != folder_path
or existing_instance["task"] != task_name
):
asset_doc = get_asset_by_name(project_name, asset_name)
subset_name = self.get_subset_name(
self.default_variant, task_name, asset_doc,
project_name, host_name
folder_entity = ayon_api.get_folder_by_path(
project_name, folder_path
)
task_entity = ayon_api.get_task_by_name(
project_name, folder_entity["id"], task_name
)
product_name = self.get_product_name(
project_name,
folder_entity,
task_entity,
self.default_variant,
host_name,
)
existing_instance["asset"] = asset_name
existing_instance["folderPath"] = folder_path
existing_instance["task"] = task_name
existing_instance["subset"] = subset_name
existing_instance["productName"] = product_name

def get_icon(self):
return qtawesome.icon("fa.file-o", color="white")
65 changes: 28 additions & 37 deletions client/ayon_openrv/plugins/load/load_frames.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

import clique

from openpype.pipeline import (
from ayon_core.pipeline import (
load,
get_representation_context
)
from openpype.pipeline.load import get_representation_path_from_context
from openpype.lib.transcoding import IMAGE_EXTENSIONS
from ayon_core.pipeline.load import get_representation_path_from_context
from ayon_core.lib.transcoding import IMAGE_EXTENSIONS

from ayon_openrv.api.pipeline import imprint_container
from ayon_openrv.api.ocio import (
Expand All @@ -22,9 +22,9 @@ class FramesLoader(load.LoaderPlugin):
"""Load frames into OpenRV"""

label = "Load Frames"
families = ["*"]
representations = ["*"]
extensions = [ext.lstrip(".") for ext in IMAGE_EXTENSIONS]
product_types = {"*"}
representations = {"*"}
extensions = {ext.lstrip(".") for ext in IMAGE_EXTENSIONS}
order = 0

icon = "code-fork"
Expand All @@ -37,7 +37,7 @@ def load(self, context, name=None, namespace=None, data=None):
filepath = str(filepath)

# node_name = "{}_{}".format(namespace, name) if namespace else name
namespace = namespace if namespace else context["asset"]["name"]
namespace = namespace if namespace else context["folder"]["name"]

loaded_node = rv.commands.addSourceVerbose([filepath])

Expand All @@ -53,12 +53,12 @@ def load(self, context, name=None, namespace=None, data=None):
loader=self.__class__.__name__
)

def update(self, container, representation):
def update(self, container, context):
node = container["node"]

context = get_representation_context(representation)
filepath = self._format_path(context)
filepath = str(filepath)
repre_entity = context["representation"]

# change path
rv.commands.setSourceMedia(node, [filepath])
Expand All @@ -72,7 +72,7 @@ def update(self, container, representation):
rv.commands.setStringProperty(node + ".media.repName",
["repname"], True)
rv.commands.setStringProperty(node + ".openpype.representation",
[str(representation["_id"])], True)
[repre_entity["id"]], True)

def remove(self, container):
node = container["node"]
Expand All @@ -95,50 +95,43 @@ def _get_sequence_range(self, context):
context (dict): Representation context.

Returns:
tuple or None: (start, end) tuple if it is an image sequence
otherwise it returns None.
Union[tuple[int, int], None]: (start, end) tuple if it is an
image sequence otherwise it returns None.

"""
version = context.get("version", {})
representation = context.get("representation", {})
repre_entity = context["representation"]

# Only images may be sequences, not videos
ext = representation.get("ext", representation.get("name"))
ext = repre_entity["context"].get("ext") or repre_entity["name"]
if f".{ext}" not in IMAGE_EXTENSIONS:
return

for doc in [representation, version]:
# Frame range can be set on version or representation.
# When set on representation it overrides version data.
data = doc.get("data", {})
start = data.get("frameStartHandle", data.get("frameStart", None))
end = data.get("frameEndHandle", data.get("frameEnd", None))
repre_attribs = repre_entity["attrib"]
# Frame range can be set on version or representation.
# When set on representation it overrides version data.

if start is None or end is None:
continue

if start != end:
return start, end
else:
# Single frame
return
repre_frame_start = repre_attribs.get("frameStart")
repre_frame_end = repre_attribs.get("frameEnd")
if repre_frame_start is not None and repre_frame_end is not None:
if repre_frame_start != repre_frame_end:
return repre_frame_start, repre_frame_end
# Single frame
return

# Fallback for image sequence that does not have frame start and frame
# end stored in the database.
# TODO: Maybe rely on rv.commands.sequenceOfFile instead?
if "frame" in representation.get("context", {}):
if "frame" in repre_entity["context"]:
# Guess the frame range from the files
files = representation.get("files", [])
files = repre_entity["files"]
if len(files) > 1:
paths = [f["path"] for f in representation["files"]]
paths = [f["path"] for f in files]
collections, _remainder = clique.assemble(paths)
if collections:
collection = collections[0]
frames = list(collection.indexes)
return frames[0], frames[-1]

return

def _format_path(self, context):
"""Format the path with correct frame range.

Expand All @@ -154,8 +147,7 @@ def _format_path(self, context):

context = copy.deepcopy(context)
representation = context["representation"]
template = representation.get("data", {}).get("template")
if not template:
if not representation["attrib"].get("template"):
# No template to find token locations for
return get_representation_path_from_context(context)

Expand All @@ -180,7 +172,6 @@ def _placeholder(key):
has_tokens = True

# Replace with our custom template that has the tokens set
representation["data"]["template"] = template
path = get_representation_path_from_context(context)

if has_tokens:
Expand Down
Loading