Merge branch 'develop' into enhancement/AY-8004_template-build-using-linked-folders

This commit is contained in:
Ondřej Samohel 2025-07-29 14:52:31 +02:00 committed by GitHub
commit ac8018d809
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 137 additions and 106 deletions

View file

@ -35,6 +35,7 @@ body:
label: Version
description: What version are you running? Look to AYON Tray
options:
- 1.5.0
- 1.4.1
- 1.4.0
- 1.3.2

View file

@ -1,5 +1,6 @@
"""Core pipeline functionality"""
from __future__ import annotations
import os
import logging
import platform
@ -16,7 +17,6 @@ from ayon_core.host import HostBase
from ayon_core.lib import (
is_in_tests,
initialize_ayon_connection,
version_up
)
from ayon_core.addon import load_addons, AddonsManager
from ayon_core.settings import get_project_settings
@ -24,12 +24,7 @@ from ayon_core.settings import get_project_settings
from .publish.lib import filter_pyblish_plugins
from .anatomy import Anatomy
from .template_data import get_template_data_with_names
from .workfile import (
get_custom_workfile_template_by_string_context,
get_workfile_template_key_from_context,
get_last_workfile,
MissingWorkdirError,
)
from .workfile import get_custom_workfile_template_by_string_context
from . import (
register_loader_plugin_path,
register_inventory_action_path,
@ -75,7 +70,7 @@ def _get_addons_manager():
def register_root(path):
"""Register currently active root"""
"""DEPRECATED Register currently active root."""
log.info("Registering root: %s" % path)
_registered_root["_"] = path
@ -94,18 +89,29 @@ def registered_root():
Returns:
dict[str, str]: Root paths.
"""
"""
warnings.warn(
"Used deprecated function 'registered_root'. Please use 'Anatomy'"
" to get roots.",
DeprecationWarning,
stacklevel=2,
)
return _registered_root["_"]
def install_host(host):
def install_host(host: HostBase) -> None:
"""Install `host` into the running Python session.
Args:
host (HostBase): A host interface object.
"""
if not isinstance(host, HostBase):
log.error(
f"Host must be a subclass of 'HostBase', got '{type(host)}'."
)
global _is_installed
_is_installed = True
@ -183,7 +189,7 @@ def install_ayon_plugins(project_name=None, host_name=None):
register_inventory_action_path(INVENTORY_PATH)
if host_name is None:
host_name = os.environ.get("AYON_HOST_NAME")
host_name = get_current_host_name()
addons_manager = _get_addons_manager()
publish_plugin_dirs = addons_manager.collect_publish_plugin_paths(
@ -366,6 +372,24 @@ def get_current_task_name():
return get_global_context()["task_name"]
def get_current_project_settings() -> dict[str, Any]:
"""Project settings for the current context project.
Returns:
dict[str, Any]: Project settings for the current context project.
Raises:
ValueError: If current project is not set.
"""
project_name = get_current_project_name()
if not project_name:
raise ValueError(
"Current project is not set. Can't get project settings."
)
return get_project_settings(project_name)
def get_current_project_entity(fields=None):
"""Helper function to get project document based on global Session.
@ -552,6 +576,7 @@ def change_current_context(
" It is not necessary to pass it in anymore."
),
DeprecationWarning,
stacklevel=2,
)
host = registered_host()
@ -580,53 +605,16 @@ def get_process_id():
def version_up_current_workfile():
"""Function to increment and save workfile
"""DEPRECATED Function to increment and save workfile.
Please use 'save_next_version' from 'ayon_core.pipeline.workfile' instead.
"""
host = registered_host()
project_name = get_current_project_name()
folder_path = get_current_folder_path()
task_name = get_current_task_name()
host_name = get_current_host_name()
template_key = get_workfile_template_key_from_context(
project_name,
folder_path,
task_name,
host_name,
warnings.warn(
"Used deprecated 'version_up_current_workfile' please use"
" 'save_next_version' from 'ayon_core.pipeline.workfile' instead.",
DeprecationWarning,
stacklevel=2,
)
anatomy = Anatomy(project_name)
data = get_template_data_with_names(
project_name, folder_path, task_name, host_name
)
data["root"] = anatomy.roots
work_template = anatomy.get_template_item("work", template_key)
# Define saving file extension
extensions = host.get_workfile_extensions()
current_file = host.get_current_workfile()
if current_file:
extensions = [os.path.splitext(current_file)[-1]]
work_root = work_template["directory"].format_strict(data)
file_template = work_template["file"].template
last_workfile_path = get_last_workfile(
work_root, file_template, data, extensions, True
)
# `get_last_workfile` will return the first expected file version
# if no files exist yet. In that case, if they do not exist we will
# want to save v001
new_workfile_path = last_workfile_path
if os.path.exists(new_workfile_path):
new_workfile_path = version_up(new_workfile_path)
# Raise an error if the parent folder doesn't exist as `host.save_workfile`
# is not supposed/able to create missing folders.
parent_folder = os.path.dirname(new_workfile_path)
if not os.path.exists(parent_folder):
raise MissingWorkdirError(
f"Work area directory '{parent_folder}' does not exist.")
host.save_workfile(new_workfile_path)
from ayon_core.pipeline.workfile import save_next_version
save_next_version()

View file

@ -720,11 +720,13 @@ def get_representation_path(representation, root=None):
str: fullpath of the representation
"""
if root is None:
from ayon_core.pipeline import registered_root
from ayon_core.pipeline import get_current_project_name, Anatomy
root = registered_root()
anatomy = Anatomy(get_current_project_name())
return get_representation_path_with_anatomy(
representation, anatomy
)
def path_from_representation():
try:
@ -772,7 +774,7 @@ def get_representation_path(representation, root=None):
dir_path, file_name = os.path.split(path)
if not os.path.exists(dir_path):
return
return None
base_name, ext = os.path.splitext(file_name)
file_name_items = None
@ -782,7 +784,7 @@ def get_representation_path(representation, root=None):
file_name_items = base_name.split("%")
if not file_name_items:
return
return None
filename_start = file_name_items[0]

View file

@ -22,9 +22,11 @@ from .utils import (
should_open_workfiles_tool_on_launch,
MissingWorkdirError,
save_workfile_info,
save_current_workfile_to,
save_workfile_with_current_context,
save_workfile_info,
save_next_version,
copy_workfile_to_context,
find_workfile_rootless_path,
)
@ -63,9 +65,11 @@ __all__ = (
"should_open_workfiles_tool_on_launch",
"MissingWorkdirError",
"save_workfile_info",
"save_current_workfile_to",
"save_workfile_with_current_context",
"save_workfile_info",
"save_next_version",
"copy_workfile_to_context",
"BuildWorkfile",

View file

@ -417,7 +417,8 @@ def save_next_version(
Args:
version (Optional[int]): Workfile version that will be used. Last
version + 1 is used if is not passed in.
comment (optional[str]): Workfile comment.
comment (optional[str]): Workfile comment. Pass '""' to clear comment.
The current workfile comment is used if it is not passed.
description (Optional[str]): Workfile description.
prepared_data (Optional[SaveWorkfileOptionalData]): Prepared data
for speed enhancements.
@ -427,6 +428,11 @@ def save_next_version(
from ayon_core.pipeline.context_tools import registered_host
host = registered_host()
current_path = host.get_current_workfile()
if not current_path:
current_path = None
else:
current_path = os.path.normpath(current_path)
context = host.get_current_context()
project_name = context["project_name"]
@ -481,7 +487,8 @@ def save_next_version(
)
rootless_dir = workdir.rootless
last_workfile = None
if version is None:
current_workfile = None
if version is None or comment is None:
workfiles = host.list_workfiles(
project_name, folder_entity, task_entity,
prepared_data=ListWorkfilesOptionalData(
@ -492,29 +499,37 @@ def save_next_version(
)
)
for workfile in workfiles:
if current_workfile is None and workfile.filepath == current_path:
current_workfile = workfile
if workfile.version is None:
continue
if (
last_workfile is None
or last_workfile.version < workfile.version
):
last_workfile = workfile
version = None
if last_workfile is not None:
version = last_workfile.version + 1
if version is None and last_workfile is not None:
version = last_workfile.version + 1
if version is None:
version = get_versioning_start(
project_name,
host.name,
task_name=task_entity["name"],
task_type=task_entity["taskType"],
product_type="workfile"
)
if version is None:
version = get_versioning_start(
project_name,
host.name,
task_name=task_entity["name"],
task_type=task_entity["taskType"],
product_type="workfile"
)
# Re-use comment from the current workfile if is not passed in
if comment is None and current_workfile is not None:
comment = current_workfile.comment
template_data["version"] = version
template_data["comment"] = comment
if comment:
template_data["comment"] = comment
# Resolve extension
# - Don't fill any if the host does not have defined any -> e.g. if host
@ -525,13 +540,13 @@ def save_next_version(
ext = None
workfile_extensions = host.get_workfile_extensions()
if workfile_extensions:
current_path = host.get_current_workfile()
if current_path:
ext = os.path.splitext(current_path)[1].lstrip(".")
ext = os.path.splitext(current_path)[1]
elif last_workfile is not None:
ext = os.path.splitext(last_workfile.filepath)[1].lstrip(".")
ext = os.path.splitext(last_workfile.filepath)[1]
else:
ext = next(iter(workfile_extensions), None)
ext = next(iter(workfile_extensions))
ext = ext.lstrip(".")
if ext:
template_data["ext"] = ext

View file

@ -1,7 +1,9 @@
import ayon_api
import ayon_api.utils
from ayon_core.host import ILoadHost
from ayon_core.pipeline import registered_host
import pyblish.api
@ -27,16 +29,23 @@ class CollectSceneLoadedVersions(pyblish.api.ContextPlugin):
def process(self, context):
host = registered_host()
if host is None:
self.log.warn("No registered host.")
self.log.warning("No registered host.")
return
if not hasattr(host, "ls"):
host_name = host.__name__
self.log.warn("Host %r doesn't have ls() implemented." % host_name)
if not isinstance(host, ILoadHost):
host_name = host.name
self.log.warning(
f"Host {host_name} does not implement ILoadHost. "
"Skipping querying of loaded versions in scene."
)
return
containers = list(host.get_containers())
if not containers:
# Opt out early if there are no containers
self.log.debug("No loaded containers found in scene.")
return
loaded_versions = []
containers = list(host.ls())
repre_ids = {
container["representation"]
for container in containers
@ -61,6 +70,7 @@ class CollectSceneLoadedVersions(pyblish.api.ContextPlugin):
# QUESTION should we add same representation id when loaded multiple
# times?
loaded_versions = []
for con in containers:
repre_id = con["representation"]
repre_entity = repre_entities_by_id.get(repre_id)
@ -80,4 +90,5 @@ class CollectSceneLoadedVersions(pyblish.api.ContextPlugin):
}
loaded_versions.append(version)
self.log.debug(f"Collected {len(loaded_versions)} loaded versions.")
context.data["loadedVersions"] = loaded_versions

View file

@ -4,6 +4,7 @@ import logging
import collections
import copy
import time
import warnings
import ayon_api
@ -175,17 +176,22 @@ def get_project_environments(project_name, project_settings=None):
def get_current_project_settings():
"""Project settings for current context project.
"""DEPRECATE Project settings for current context project.
Function requires access to pipeline context which is in
'ayon_core.pipeline'.
Returns:
dict[str, Any]: Project settings for current context project.
Project name should be stored in environment variable `AYON_PROJECT_NAME`.
This function should be used only in host context where environment
variable must be set and should not happen that any part of process will
change the value of the environment variable.
"""
project_name = os.environ.get("AYON_PROJECT_NAME")
if not project_name:
raise ValueError(
"Missing context project in environment"
" variable `AYON_PROJECT_NAME`."
)
return get_project_settings(project_name)
warnings.warn(
"Used deprecated function 'get_current_project_settings' in"
" 'ayon_core.settings'. The function was moved to"
" 'ayon_core.pipeline.context_tools'.",
DeprecationWarning,
stacklevel=2
)
from ayon_core.pipeline.context_tools import get_current_project_settings
return get_current_project_settings()

View file

@ -399,7 +399,11 @@ class ActionsModel:
return cache.get_data()
try:
response = ayon_api.post("actions/list", **request_data)
# 'variant' query is supported since AYON backend 1.10.4
query = urlencode({"variant": self._variant})
response = ayon_api.post(
f"actions/list?{query}", **request_data
)
response.raise_for_status()
except Exception:
self.log.warning("Failed to collect webactions.", exc_info=True)

View file

@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
"""Package declaring AYON addon 'core' version."""
__version__ = "1.4.1+dev"
__version__ = "1.5.0+dev"

View file

@ -1,6 +1,6 @@
name = "core"
title = "Core"
version = "1.4.1+dev"
version = "1.5.0+dev"
client_dir = "ayon_core"

View file

@ -5,7 +5,7 @@
[tool.poetry]
name = "ayon-core"
version = "1.4.1+dev"
version = "1.5.0+dev"
description = ""
authors = ["Ynput Team <team@ynput.io>"]
readme = "README.md"