mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 16:34:53 +01:00
* General: Connect to AYON server (base) (#3924) * implemented 'get_workfile_info' in entities * removed 'prepare_asset_update_data' which is not used * disable settings and project manager if in v4 mode * prepared conversion helper functions for v4 entities * prepared conversion functions for hero versions * fix hero versions * implemented get_archived_representations * fix get latest versions * return prepared changes * handle archived representation * raise exception on failed json conversion * map archived to active properly * make sure default fields are added * fix conversion of hero version entity * fix conversion of archived representations * fix some conversions of representations and versions * changed active behavior in queries * fixed hero versions * implemented basic thumbnail caching * added raw variants of crud methods * implemented methods to get and create thumbnail * fix from flat dict * implemented some basic folder conversion for updates * fix thumbnail updates for version * implemented v4 thumbnail integrator * simplified data mapping * 'get_thumbnail' function also expect entity type and entity id for which is the thumbnail received * implemented 'get_thumbnail' for server * fix how thumbnail id is received from entity * removed unnecessary method 'get_thumbnail_id_from_source' * implemented thumbnail resolver for v4 * removed unnecessary print * move create and delete project directly to server api * disable local settings action too on v4 * OP-3521 - added method to check and download updated addons from v4 server * OP-3521 - added more descriptive error message for missing source * OP-3521 - added default implementation of addon downloader to import * OP-3521 - added check for dependency package zips WIP - server doesn't contain required endpoint. Testing only with mockup data for now. * OP-3521 - fixed parsing of DependencyItem Added Server Url type and ServerAddonDownloader - v4 server doesn't know its own DNS for static files so it is sending unique name and url must be created during runtime. * OP-3521 - fixed creation of targed directories * change nev keys to look for and don't set them automatically * fix task type conversion * implemented base of loading v4 addons in v3 * Refactored argument name in Downloaders * Updated parsing to DependencyItem according to current schema * Implemented downloading of package from server * Updated resolving of failures Uses Enum items. * Introduced passing of authorization token Better to inject it than to have it from env var. * Remove weird parsing of server_url Not necessary, endpoints have same prefix. * Fix doubling asset version name in addons folder Zip file should already contain `addonName_addonVersion` as first subfolder * Fix doubling asset version name in addons folder Zip file should already contain `addonName_addonVersion` as first subfolder * Made server_endpoint optional Argument should be better for testing, but for calling from separate methods it would be better to encapsulate it. Removed unwanted temporary productionPackage value * Use existing method to pull addon info from Server to load v4 version of addon * Raise exception when server doesn't have any production dependency package * added ability to specify v3 alias of addon name * expect v3_alias as uppered constant * Re-implemented method to get addon info Previous implementation wouldn't work in Python2 hosts. Will be refactored in the future. * fix '__getattr__' * added ayon api to pyproject.toml and lock file * use ayon api in common connection * added mapping for label * use ayon_api in client codebase * separated clearing cache of url and username * bump ayon api version * rename env 'OP4_TEST' to 'USE_AYON_SERVER' * Move and renamend get_addons_info to get_addons_info_as_dict in addon_distribution Should be moved to ayon_api later * Replaced requests calls with ayon_api * Replaced OP4_TEST_ENABLED with AYON_SERVER_ENABLED fixed endpoints * Hound * Hound * OP-3521 - fix wrong key in get_representation_parents parents overloads parents * OP-3521 - changes for v4 of SiteSync addon * OP-3521 - fix names * OP-3521 - remove storing project_name It should be safer to go thorug self.dbcon apparently * OP-3521 - remove unwanted "context["folder"]" can be only in dummy test data * OP-3521 - move site sync loaders to addon * Use only project instead of self.project * OP-3521 - added missed get_progress_for_repre * base of settings conversion script * simplified ayon functions in start.py * added loading of settings from ayon server * added a note about colors * fix global and local settings functions * AvalonMongoDB is not using mongo connection on ayon server enabled * 'get_dynamic_modules_dirs' is not checking system settings for paths in setting * log viewer is disabled when ayon server is enabled * basic logic of enabling/disabled addons * don't use mongo logging if ayon server is enabled * update ayon api * bump ayon api again * use ayon_api to get addons info in modules/base * update ayon api * moved helper functions to get addons and dependencies dir to common functions * Initialization of AddonInfo is not crashing on unkonwn sources * renamed 'DependencyDownloader' to 'AyonServerDownloader' * renamed function 'default_addon_downloader' to 'get_default_addon_downloader' * Added ability to convert 'WebAddonSource' to 'ServerResourceSorce' * missing dependency package on server won't cause crash * data sent to downloaders don't contain ayon specific headers * modified addon distribution to not duplicate 'ayon_api' functionality * fix doubled function defintioin * unzip client file to addon destination * formatting - unify quotes * disable usage of mongo connection if in ayon mode * renamed window.py to login_window.py * added webpublisher settings conversion * added maya conversion function * reuse variable * reuse variable (similar to previous commit) * fix ayon addons loading * fix typo 'AyonSettingsCahe' -> 'AyonSettingsCache' * fix enabled state changes * fix rr_path in royal render conversion * avoid mongo calls in AYON state * implemented custom AYON start script * fix formatting (after black) * ayon_start cleanup * 'get_addons_dir' and 'get_dependencies_dir' store value to environment variable * add docstrings to local dir functions * addon info has full name * fix modules enabled states * removed unused 'run_disk_mapping_commands' * removed ayon logic from 'start.py' * fix warning message * renamed 'openpype_common' to 'ayon_common' * removed unused import * don't import igniter * removed startup validations of third parties * change what's shown in version info * fix which keys are applied from ayon values * fix method name * get applications from attribs * Implemented UI basics to be able change user or logout * merged server.py and credentials.py * add more metadata to urls * implemented change token * implemented change user ui functionality * implemented change user ui * modify window to handle username and token value * pass username to add server * fix show UI cases * added loggin action to tray * update ayon api * added missing dependency * convert applications to config in a right way * initial implementation of 'nuke' settings conversion * removed few nuke comments * implemented hiero conversion * added imageio conversion * added run ayon tray script * fix few settings conversions * Renamed class of source classes as they are not just for addons * implemented objec to track source transfer progress * Implemented distribution item with multiple sources * Implemented ayon distribution wrapper to care about multiple things during distribution * added 'cleanup' method for downlaoders * download gets tranfer progress object * Change UploadState enum * added missing imports * use AyonDistribution in ayon_start.py * removed unused functions * removed implemented TODOs * fix import * fix key used for Web source * removed temp development fix * formatting fix * keep information if source require distribution * handle 'require_distribution' attribute in distribution process * added path attribute to server source * added option to pass addons infor to ayon distribution * fix tests * fix formatting * Fix typo * Fix typo * remove '_try_convert_to_server_source' * renamed attributes and methods to match their content * it is possible to pass dependency package info to AyonDistribution * fix called methods in tests * added public properties for error message and error detail * Added filename to WebSourceInfo Useful for GDrive sharable links where target file name is unknown/unparsable, it should be provided explicitly. * unify source conversion by adding 'convert_source' function * Fix error message Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com> * added docstring for 'transfer_progress' * don't create metadata file on read * added few docstrings * add default folder fields to folder/task queries * fix generators * add dependencies when runnign from code * add sys paths from distribution to pythonpath env * fix missing applications * added missing conversions for maya renderers * fix formatting * update ayon api * fix hashes in lock file * Use better exception Co-authored-by: Ondřej Samohel <33513211+antirotor@users.noreply.github.com> * Use Python 3 syntax Co-authored-by: Ondřej Samohel <33513211+antirotor@users.noreply.github.com> * apply some of sugested changes in ayon_start * added some docstrings and suggested modifications * copy create env from develop * fix rendersettings conversion * change code by suggestions * added missing args to docstring * added missing docstrings * separated downloader and download factory * fix ayon settings * added some basic file docstring to ayon_settings * join else conditions * fix project settings conversion * fix created at conversion * fix workfile info query * fix publisher UI * added utils function 'get_ayon_appdirs' * fix 'get_all_current_info' * fix server url assignment when url is set * updated ayon api * added utils functions to create local site id for ayon * added helper functions to create global connection * create global connection in ayon start to start use site id * use ayon site id in ayon mode * formatting cleanup * added header docstring * fixes after ayon_api update * load addons from ynput appdirs * fix function call * added docstring * update ayon pyton api * fix settings access * use ayon_api to get root overrides in Anatomy * bumbayon version to 0.1.13 * nuke: fixing settings keys from settings * fix burnins definitions * change v4 to AYON in thumbnail integrate * fix one more v4 information * Fixes after rebase * fix extract burnin conversion * additional fix of extract burnin * SiteSync:added missed loaders or v3 compatibility (#4587) * Added site sync loaders for v3 compatibility * Fix get_progress_for_repre * use 'files.name' instead of 'files.baseName' * update ayon api to 0.1.14 * add common to include files * change arguments for hero version creation * skip shotgrid settings conversion if different ayon addon is used * added ayon icons * fix labels of application variants * added option to show login window always on top * login window on invalid credentials is always on top * update ayon api * update ayon api * add entityType to project and folders * AYON: Editorial hierarchy creation (#4699) * disable extract hierarchy avalon when ayon mode is enabled * implemented extract hierarchy to AYON --------- Co-authored-by: Petr Kalis <petr.kalis@gmail.com> Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com> Co-authored-by: Ondřej Samohel <33513211+antirotor@users.noreply.github.com> Co-authored-by: Jakub Jezek <jakubjezek001@gmail.com> * replace 'legacy_io' with context functions in load plugins * added 'get_global_context' to pipeline init * use context getters instead of legacy_io in publish plugins * use data on context instead of 'legacy_io' in submit publish job * skip query of asset docs in collect nuke reads * use context functions on other places * 'list_looks' expects project name * remove 'get_context_title' * don't pass AvalonMongoDB to prelaunch hooks * change how context is calculated in hiero * implemented function 'get_fps_for_current_context' for maya * initialize '_image_dir' and '_image_prefixes' in init * legacy creator is using 'get_current_project_name' * fill docstrings * use context functions in workfile builders * hound fixes * 'create_workspace_mel' can expect project settings * swapped order of arguments * use information from instance/context data * Use self.project_name in workfiles tool Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com> * Remove outdated todo Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com> * don't query project document in nuke lib * Fix access to context data * Use right function to get project name Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com> * fix submit max deadline and swap order of arguments * added 'get_context_label' to nuke * fix import * fix typo 'curent_context' -> 'current_context' * fix project_setting variable * fix submit publish job environments * use task from context * Removed unused import --------- Co-authored-by: Petr Kalis <petr.kalis@gmail.com> Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com> Co-authored-by: Ondřej Samohel <33513211+antirotor@users.noreply.github.com> Co-authored-by: Jakub Jezek <jakubjezek001@gmail.com>
655 lines
18 KiB
Python
655 lines
18 KiB
Python
"""Core pipeline functionality"""
|
|
|
|
import os
|
|
import json
|
|
import types
|
|
import logging
|
|
import platform
|
|
import uuid
|
|
|
|
import pyblish.api
|
|
from pyblish.lib import MessageHandler
|
|
|
|
import openpype
|
|
from openpype.host import HostBase
|
|
from openpype.client import (
|
|
get_project,
|
|
get_asset_by_id,
|
|
get_asset_by_name,
|
|
version_is_latest,
|
|
)
|
|
from openpype.lib.events import emit_event
|
|
from openpype.modules import load_modules, ModulesManager
|
|
from openpype.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_workfile_template_key,
|
|
get_custom_workfile_template_by_string_context,
|
|
)
|
|
from . import (
|
|
legacy_io,
|
|
register_loader_plugin_path,
|
|
register_inventory_action_path,
|
|
register_creator_plugin_path,
|
|
deregister_loader_plugin_path,
|
|
deregister_inventory_action_path,
|
|
)
|
|
|
|
|
|
_is_installed = False
|
|
_process_id = None
|
|
_registered_root = {"_": ""}
|
|
_registered_host = {"_": None}
|
|
# Keep modules manager (and it's modules) in memory
|
|
# - that gives option to register modules' callbacks
|
|
_modules_manager = None
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
PACKAGE_DIR = os.path.dirname(os.path.abspath(openpype.__file__))
|
|
PLUGINS_DIR = os.path.join(PACKAGE_DIR, "plugins")
|
|
|
|
# Global plugin paths
|
|
PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish")
|
|
LOAD_PATH = os.path.join(PLUGINS_DIR, "load")
|
|
INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory")
|
|
|
|
|
|
def _get_modules_manager():
|
|
"""Get or create modules manager for host installation.
|
|
|
|
This is not meant for public usage. Reason is to keep modules
|
|
in memory of process to be able trigger their event callbacks if they
|
|
need any.
|
|
|
|
Returns:
|
|
ModulesManager: Manager wrapping discovered modules.
|
|
"""
|
|
|
|
global _modules_manager
|
|
if _modules_manager is None:
|
|
_modules_manager = ModulesManager()
|
|
return _modules_manager
|
|
|
|
|
|
def register_root(path):
|
|
"""Register currently active root"""
|
|
log.info("Registering root: %s" % path)
|
|
_registered_root["_"] = path
|
|
|
|
|
|
def registered_root():
|
|
"""Return currently registered root"""
|
|
root = _registered_root["_"]
|
|
if root:
|
|
return root
|
|
|
|
root = legacy_io.Session.get("AVALON_PROJECTS")
|
|
if root:
|
|
return os.path.normpath(root)
|
|
return ""
|
|
|
|
|
|
def install_host(host):
|
|
"""Install `host` into the running Python session.
|
|
|
|
Args:
|
|
host (module): A Python module containing the Avalon
|
|
avalon host-interface.
|
|
"""
|
|
global _is_installed
|
|
|
|
_is_installed = True
|
|
|
|
legacy_io.install()
|
|
modules_manager = _get_modules_manager()
|
|
|
|
missing = list()
|
|
for key in ("AVALON_PROJECT", "AVALON_ASSET"):
|
|
if key not in legacy_io.Session:
|
|
missing.append(key)
|
|
|
|
assert not missing, (
|
|
"%s missing from environment, %s" % (
|
|
", ".join(missing),
|
|
json.dumps(legacy_io.Session, indent=4, sort_keys=True)
|
|
))
|
|
|
|
project_name = legacy_io.Session["AVALON_PROJECT"]
|
|
log.info("Activating %s.." % project_name)
|
|
|
|
# Optional host install function
|
|
if hasattr(host, "install"):
|
|
host.install()
|
|
|
|
register_host(host)
|
|
|
|
def modified_emit(obj, record):
|
|
"""Method replacing `emit` in Pyblish's MessageHandler."""
|
|
record.msg = record.getMessage()
|
|
obj.records.append(record)
|
|
|
|
MessageHandler.emit = modified_emit
|
|
|
|
if os.environ.get("OPENPYPE_REMOTE_PUBLISH"):
|
|
# target "farm" == rendering on farm, expects OPENPYPE_PUBLISH_DATA
|
|
# target "remote" == remote execution, installs host
|
|
print("Registering pyblish target: remote")
|
|
pyblish.api.register_target("remote")
|
|
else:
|
|
pyblish.api.register_target("local")
|
|
|
|
project_name = os.environ.get("AVALON_PROJECT")
|
|
host_name = os.environ.get("AVALON_APP")
|
|
|
|
# Give option to handle host installation
|
|
for module in modules_manager.get_enabled_modules():
|
|
module.on_host_install(host, host_name, project_name)
|
|
|
|
install_openpype_plugins(project_name, host_name)
|
|
|
|
|
|
def install_openpype_plugins(project_name=None, host_name=None):
|
|
# Make sure modules are loaded
|
|
load_modules()
|
|
|
|
log.info("Registering global plug-ins..")
|
|
pyblish.api.register_plugin_path(PUBLISH_PATH)
|
|
pyblish.api.register_discovery_filter(filter_pyblish_plugins)
|
|
register_loader_plugin_path(LOAD_PATH)
|
|
register_inventory_action_path(INVENTORY_PATH)
|
|
|
|
if host_name is None:
|
|
host_name = os.environ.get("AVALON_APP")
|
|
|
|
modules_manager = _get_modules_manager()
|
|
publish_plugin_dirs = modules_manager.collect_publish_plugin_paths(
|
|
host_name)
|
|
for path in publish_plugin_dirs:
|
|
pyblish.api.register_plugin_path(path)
|
|
|
|
create_plugin_paths = modules_manager.collect_create_plugin_paths(
|
|
host_name)
|
|
for path in create_plugin_paths:
|
|
register_creator_plugin_path(path)
|
|
|
|
load_plugin_paths = modules_manager.collect_load_plugin_paths(
|
|
host_name)
|
|
for path in load_plugin_paths:
|
|
register_loader_plugin_path(path)
|
|
|
|
inventory_action_paths = modules_manager.collect_inventory_action_paths(
|
|
host_name)
|
|
for path in inventory_action_paths:
|
|
register_inventory_action_path(path)
|
|
|
|
if project_name is None:
|
|
project_name = os.environ.get("AVALON_PROJECT")
|
|
|
|
# Register studio specific plugins
|
|
if project_name:
|
|
anatomy = Anatomy(project_name)
|
|
anatomy.set_root_environments()
|
|
register_root(anatomy.roots)
|
|
|
|
project_settings = get_project_settings(project_name)
|
|
platform_name = platform.system().lower()
|
|
project_plugins = (
|
|
project_settings
|
|
.get("global", {})
|
|
.get("project_plugins", {})
|
|
.get(platform_name)
|
|
) or []
|
|
for path in project_plugins:
|
|
try:
|
|
path = str(path.format(**os.environ))
|
|
except KeyError:
|
|
pass
|
|
|
|
if not path or not os.path.exists(path):
|
|
continue
|
|
|
|
pyblish.api.register_plugin_path(path)
|
|
register_loader_plugin_path(path)
|
|
register_creator_plugin_path(path)
|
|
register_inventory_action_path(path)
|
|
|
|
|
|
def uninstall_host():
|
|
"""Undo all of what `install()` did"""
|
|
host = registered_host()
|
|
|
|
try:
|
|
host.uninstall()
|
|
except AttributeError:
|
|
pass
|
|
|
|
log.info("Deregistering global plug-ins..")
|
|
pyblish.api.deregister_plugin_path(PUBLISH_PATH)
|
|
pyblish.api.deregister_discovery_filter(filter_pyblish_plugins)
|
|
deregister_loader_plugin_path(LOAD_PATH)
|
|
deregister_inventory_action_path(INVENTORY_PATH)
|
|
log.info("Global plug-ins unregistred")
|
|
|
|
deregister_host()
|
|
|
|
legacy_io.uninstall()
|
|
|
|
log.info("Successfully uninstalled Avalon!")
|
|
|
|
|
|
def is_installed():
|
|
"""Return state of installation
|
|
|
|
Returns:
|
|
True if installed, False otherwise
|
|
|
|
"""
|
|
|
|
return _is_installed
|
|
|
|
|
|
def register_host(host):
|
|
"""Register a new host for the current process
|
|
|
|
Arguments:
|
|
host (ModuleType): A module implementing the
|
|
Host API interface. See the Host API
|
|
documentation for details on what is
|
|
required, or browse the source code.
|
|
|
|
"""
|
|
|
|
_registered_host["_"] = host
|
|
|
|
|
|
def registered_host():
|
|
"""Return currently registered host"""
|
|
return _registered_host["_"]
|
|
|
|
|
|
def deregister_host():
|
|
_registered_host["_"] = None
|
|
|
|
|
|
def debug_host():
|
|
"""A debug host, useful to debugging features that depend on a host"""
|
|
|
|
host = types.ModuleType("debugHost")
|
|
|
|
def ls():
|
|
containers = [
|
|
{
|
|
"representation": "ee-ft-a-uuid1",
|
|
"schema": "openpype:container-1.0",
|
|
"name": "Bruce01",
|
|
"objectName": "Bruce01_node",
|
|
"namespace": "_bruce01_",
|
|
"version": 3,
|
|
},
|
|
{
|
|
"representation": "aa-bc-s-uuid2",
|
|
"schema": "openpype:container-1.0",
|
|
"name": "Bruce02",
|
|
"objectName": "Bruce01_node",
|
|
"namespace": "_bruce02_",
|
|
"version": 2,
|
|
}
|
|
]
|
|
|
|
for container in containers:
|
|
yield container
|
|
|
|
host.__dict__.update({
|
|
"ls": ls,
|
|
"open_file": lambda fname: None,
|
|
"save_file": lambda fname: None,
|
|
"current_file": lambda: os.path.expanduser("~/temp.txt"),
|
|
"has_unsaved_changes": lambda: False,
|
|
"work_root": lambda: os.path.expanduser("~/temp"),
|
|
"file_extensions": lambda: ["txt"],
|
|
})
|
|
|
|
return host
|
|
|
|
|
|
def get_current_host_name():
|
|
"""Current host name.
|
|
|
|
Function is based on currently registered host integration or environment
|
|
variable 'AVALON_APP'.
|
|
|
|
Returns:
|
|
Union[str, None]: Name of host integration in current process or None.
|
|
"""
|
|
|
|
host = registered_host()
|
|
if isinstance(host, HostBase):
|
|
return host.name
|
|
return os.environ.get("AVALON_APP")
|
|
|
|
|
|
def get_global_context():
|
|
"""Global context defined in environment variables.
|
|
|
|
Values here may not reflect current context of host integration. The
|
|
function can be used on startup before a host is registered.
|
|
|
|
Use 'get_current_context' to make sure you'll get current host integration
|
|
context info.
|
|
|
|
Example:
|
|
{
|
|
"project_name": "Commercial",
|
|
"asset_name": "Bunny",
|
|
"task_name": "Animation",
|
|
}
|
|
|
|
Returns:
|
|
dict[str, Union[str, None]]: Context defined with environment
|
|
variables.
|
|
"""
|
|
|
|
return {
|
|
"project_name": os.environ.get("AVALON_PROJECT"),
|
|
"asset_name": os.environ.get("AVALON_ASSET"),
|
|
"task_name": os.environ.get("AVALON_TASK"),
|
|
}
|
|
|
|
|
|
def get_current_context():
|
|
host = registered_host()
|
|
if isinstance(host, HostBase):
|
|
return host.get_current_context()
|
|
return get_global_context()
|
|
|
|
|
|
def get_current_project_name():
|
|
host = registered_host()
|
|
if isinstance(host, HostBase):
|
|
return host.get_current_project_name()
|
|
return get_global_context()["project_name"]
|
|
|
|
|
|
def get_current_asset_name():
|
|
host = registered_host()
|
|
if isinstance(host, HostBase):
|
|
return host.get_current_asset_name()
|
|
return get_global_context()["asset_name"]
|
|
|
|
|
|
def get_current_task_name():
|
|
host = registered_host()
|
|
if isinstance(host, HostBase):
|
|
return host.get_current_task_name()
|
|
return get_global_context()["task_name"]
|
|
|
|
|
|
def get_current_project(fields=None):
|
|
"""Helper function to get project document based on global Session.
|
|
|
|
This function should be called only in process where host is installed.
|
|
|
|
Returns:
|
|
dict: Project document.
|
|
None: Project is not set.
|
|
"""
|
|
|
|
project_name = get_current_project_name()
|
|
return get_project(project_name, fields=fields)
|
|
|
|
|
|
def get_current_project_asset(asset_name=None, asset_id=None, fields=None):
|
|
"""Helper function to get asset document based on global Session.
|
|
|
|
This function should be called only in process where host is installed.
|
|
|
|
Asset is found out based on passed asset name or id (not both). Asset name
|
|
is not used for filtering if asset id is passed. When both asset name and
|
|
id are missing then asset name from current process is used.
|
|
|
|
Args:
|
|
asset_name (str): Name of asset used for filter.
|
|
asset_id (Union[str, ObjectId]): Asset document id. If entered then
|
|
is used as only filter.
|
|
fields (Union[List[str], None]): Limit returned data of asset documents
|
|
to specific keys.
|
|
|
|
Returns:
|
|
dict: Asset document.
|
|
None: Asset is not set or not exist.
|
|
"""
|
|
|
|
project_name = get_current_project_name()
|
|
if asset_id:
|
|
return get_asset_by_id(project_name, asset_id, fields=fields)
|
|
|
|
if not asset_name:
|
|
asset_name = get_current_asset_name()
|
|
# Skip if is not set even on context
|
|
if not asset_name:
|
|
return None
|
|
return get_asset_by_name(project_name, asset_name, fields=fields)
|
|
|
|
|
|
def is_representation_from_latest(representation):
|
|
"""Return whether the representation is from latest version
|
|
|
|
Args:
|
|
representation (dict): The representation document from the database.
|
|
|
|
Returns:
|
|
bool: Whether the representation is of latest version.
|
|
"""
|
|
|
|
project_name = get_current_project_name()
|
|
return version_is_latest(project_name, representation["parent"])
|
|
|
|
|
|
def get_template_data_from_session(session=None, system_settings=None):
|
|
"""Template data for template fill from session keys.
|
|
|
|
Args:
|
|
session (Union[Dict[str, str], None]): The Session to use. If not
|
|
provided use the currently active global Session.
|
|
system_settings (Union[Dict[str, Any], Any]): Prepared system settings.
|
|
Optional are auto received if not passed.
|
|
|
|
Returns:
|
|
Dict[str, Any]: All available data from session.
|
|
"""
|
|
|
|
if session is None:
|
|
session = legacy_io.Session
|
|
|
|
project_name = session["AVALON_PROJECT"]
|
|
asset_name = session["AVALON_ASSET"]
|
|
task_name = session["AVALON_TASK"]
|
|
host_name = session["AVALON_APP"]
|
|
|
|
return get_template_data_with_names(
|
|
project_name, asset_name, task_name, host_name, system_settings
|
|
)
|
|
|
|
|
|
def get_workdir_from_session(session=None, template_key=None):
|
|
"""Template data for template fill from session keys.
|
|
|
|
Args:
|
|
session (Union[Dict[str, str], None]): The Session to use. If not
|
|
provided use the currently active global Session.
|
|
template_key (str): Prepared template key from which workdir is
|
|
calculated.
|
|
|
|
Returns:
|
|
str: Workdir path.
|
|
"""
|
|
|
|
if session is None:
|
|
session = legacy_io.Session
|
|
project_name = session["AVALON_PROJECT"]
|
|
host_name = session["AVALON_APP"]
|
|
template_data = get_template_data_from_session(session)
|
|
|
|
if not template_key:
|
|
task_type = template_data["task"]["type"]
|
|
template_key = get_workfile_template_key(
|
|
task_type,
|
|
host_name,
|
|
project_name=project_name
|
|
)
|
|
|
|
anatomy = Anatomy(project_name)
|
|
template_obj = anatomy.templates_obj[template_key]["folder"]
|
|
path = template_obj.format_strict(template_data)
|
|
if path:
|
|
path = os.path.normpath(path)
|
|
return path
|
|
|
|
|
|
def get_custom_workfile_template_from_session(
|
|
session=None, project_settings=None
|
|
):
|
|
"""Filter and fill workfile template profiles by current context.
|
|
|
|
Current context is defined by `legacy_io.Session`. That's why this
|
|
function should be used only inside host where context is set and stable.
|
|
|
|
Args:
|
|
session (Union[None, Dict[str, str]]): Session from which are taken
|
|
data.
|
|
project_settings(Dict[str, Any]): Template profiles from settings.
|
|
|
|
Returns:
|
|
str: Path to template or None if none of profiles match current
|
|
context. (Existence of formatted path is not validated.)
|
|
"""
|
|
|
|
if session is None:
|
|
session = legacy_io.Session
|
|
|
|
return get_custom_workfile_template_by_string_context(
|
|
session["AVALON_PROJECT"],
|
|
session["AVALON_ASSET"],
|
|
session["AVALON_TASK"],
|
|
session["AVALON_APP"],
|
|
project_settings=project_settings
|
|
)
|
|
|
|
|
|
def compute_session_changes(
|
|
session, asset_doc, task_name, template_key=None
|
|
):
|
|
"""Compute the changes for a session object on task under asset.
|
|
|
|
Function does not change the session object, only returns changes.
|
|
|
|
Args:
|
|
session (Dict[str, str]): The initial session to compute changes to.
|
|
This is required for computing the full Work Directory, as that
|
|
also depends on the values that haven't changed.
|
|
asset_doc (Dict[str, Any]): Asset document to switch to.
|
|
task_name (str): Name of task to switch to.
|
|
template_key (Union[str, None]): Prepare workfile template key in
|
|
anatomy templates.
|
|
|
|
Returns:
|
|
Dict[str, str]: Changes in the Session dictionary.
|
|
"""
|
|
|
|
changes = {}
|
|
|
|
# Get asset document and asset
|
|
if not asset_doc:
|
|
task_name = None
|
|
asset_name = None
|
|
else:
|
|
asset_name = asset_doc["name"]
|
|
|
|
# Detect any changes compared session
|
|
mapping = {
|
|
"AVALON_ASSET": asset_name,
|
|
"AVALON_TASK": task_name,
|
|
}
|
|
changes = {
|
|
key: value
|
|
for key, value in mapping.items()
|
|
if value != session.get(key)
|
|
}
|
|
if not changes:
|
|
return changes
|
|
|
|
# Compute work directory (with the temporary changed session so far)
|
|
changed_session = session.copy()
|
|
changed_session.update(changes)
|
|
|
|
workdir = None
|
|
if asset_doc:
|
|
workdir = get_workdir_from_session(
|
|
changed_session, template_key
|
|
)
|
|
|
|
changes["AVALON_WORKDIR"] = workdir
|
|
|
|
return changes
|
|
|
|
|
|
def change_current_context(asset_doc, task_name, template_key=None):
|
|
"""Update active Session to a new task work area.
|
|
|
|
This updates the live Session to a different task under asset.
|
|
|
|
Args:
|
|
asset_doc (Dict[str, Any]): The asset document to set.
|
|
task_name (str): The task to set under asset.
|
|
template_key (Union[str, None]): Prepared template key to be used for
|
|
workfile template in Anatomy.
|
|
|
|
Returns:
|
|
Dict[str, str]: The changed key, values in the current Session.
|
|
"""
|
|
|
|
changes = compute_session_changes(
|
|
legacy_io.Session,
|
|
asset_doc,
|
|
task_name,
|
|
template_key=template_key
|
|
)
|
|
|
|
# Update the Session and environments. Pop from environments all keys with
|
|
# value set to None.
|
|
for key, value in changes.items():
|
|
legacy_io.Session[key] = value
|
|
if value is None:
|
|
os.environ.pop(key, None)
|
|
else:
|
|
os.environ[key] = value
|
|
|
|
data = changes.copy()
|
|
# Convert env keys to human readable keys
|
|
data["project_name"] = legacy_io.Session["AVALON_PROJECT"]
|
|
data["asset_name"] = legacy_io.Session["AVALON_ASSET"]
|
|
data["task_name"] = legacy_io.Session["AVALON_TASK"]
|
|
|
|
# Emit session change
|
|
emit_event("taskChanged", data)
|
|
|
|
return changes
|
|
|
|
|
|
def get_process_id():
|
|
"""Fake process id created on demand using uuid.
|
|
|
|
Can be used to create process specific folders in temp directory.
|
|
|
|
Returns:
|
|
str: Process id.
|
|
"""
|
|
|
|
global _process_id
|
|
if _process_id is None:
|
|
_process_id = str(uuid.uuid4())
|
|
return _process_id
|