diff --git a/client/ayon_core/addon/base.py b/client/ayon_core/addon/base.py index b10629ede8..b9ecff4233 100644 --- a/client/ayon_core/addon/base.py +++ b/client/ayon_core/addon/base.py @@ -28,16 +28,16 @@ from .interfaces import ( ) # Files that will be always ignored on addons import -IGNORED_FILENAMES = ( +IGNORED_FILENAMES = { "__pycache__", -) +} # Files ignored on addons import from "./ayon_core/modules" -IGNORED_DEFAULT_FILENAMES = ( +IGNORED_DEFAULT_FILENAMES = { "__init__.py", "base.py", "interfaces.py", "click_wrap.py", -) +} # When addon was moved from ayon-core codebase # - this is used to log the missing addon @@ -411,82 +411,56 @@ def _load_addons_in_core( ): # Add current directory at first place # - has small differences in import logic - hosts_dir = os.path.join(AYON_CORE_ROOT, "hosts") modules_dir = os.path.join(AYON_CORE_ROOT, "modules") + if not os.path.exists(modules_dir): + log.warning( + f"Could not find path when loading AYON addons \"{modules_dir}\"" + ) + return - for dirpath in {hosts_dir, modules_dir}: - if not os.path.exists(dirpath): - log.warning(( - "Could not find path when loading AYON addons \"{}\"" - ).format(dirpath)) + ignored_filenames = IGNORED_FILENAMES | IGNORED_DEFAULT_FILENAMES + + for filename in os.listdir(modules_dir): + # Ignore filenames + if filename in ignored_filenames: continue - is_in_modules_dir = dirpath == modules_dir - ignored_filenames = set() - if is_in_modules_dir: - ignored_filenames = set(IGNORED_DEFAULT_FILENAMES) + fullpath = os.path.join(modules_dir, filename) + basename, ext = os.path.splitext(filename) - for filename in os.listdir(dirpath): - # Ignore filenames - if filename in IGNORED_FILENAMES or filename in ignored_filenames: + if basename in ignore_addon_names: + continue + + # Validations + if os.path.isdir(fullpath): + # Check existence of init file + init_path = os.path.join(fullpath, "__init__.py") + if not os.path.exists(init_path): + log.debug(( + "Addon directory does not contain __init__.py" + f" file {fullpath}" + )) continue - fullpath = os.path.join(dirpath, filename) - basename, ext = os.path.splitext(filename) + elif ext != ".py": + continue - if basename in ignore_addon_names: - continue + # TODO add more logic how to define if folder is addon or not + # - check manifest and content of manifest + try: + # Don't import dynamically current directory modules + new_import_str = f"{modules_key}.{basename}" - # Validations - if os.path.isdir(fullpath): - # Check existence of init file - init_path = os.path.join(fullpath, "__init__.py") - if not os.path.exists(init_path): - log.debug(( - "Addon directory does not contain __init__.py" - " file {}" - ).format(fullpath)) - continue + import_str = f"ayon_core.modules.{basename}" + default_module = __import__(import_str, fromlist=("", )) + sys.modules[new_import_str] = default_module + setattr(openpype_modules, basename, default_module) - elif ext not in (".py", ): - continue - - # TODO add more logic how to define if folder is addon or not - # - check manifest and content of manifest - try: - # Don't import dynamically current directory modules - new_import_str = "{}.{}".format(modules_key, basename) - if is_in_modules_dir: - import_str = "ayon_core.modules.{}".format(basename) - default_module = __import__(import_str, fromlist=("", )) - sys.modules[new_import_str] = default_module - setattr(openpype_modules, basename, default_module) - - else: - import_str = "ayon_core.hosts.{}".format(basename) - # Until all hosts are converted to be able use them as - # modules is this error check needed - try: - default_module = __import__( - import_str, fromlist=("", ) - ) - sys.modules[new_import_str] = default_module - setattr(openpype_modules, basename, default_module) - - except Exception: - log.warning( - "Failed to import host folder {}".format(basename), - exc_info=True - ) - - except Exception: - if is_in_modules_dir: - msg = "Failed to import in-core addon '{}'.".format( - basename - ) - else: - msg = "Failed to import addon '{}'.".format(fullpath) - log.error(msg, exc_info=True) + except Exception: + log.error( + f"Failed to import in-core addon '{basename}'.", + exc_info=True + ) def _load_addons(): diff --git a/client/ayon_core/cli_commands.py b/client/ayon_core/cli_commands.py index f71588e196..35b7e294de 100644 --- a/client/ayon_core/cli_commands.py +++ b/client/ayon_core/cli_commands.py @@ -64,9 +64,10 @@ class Commands: get_global_context, ) - # Register target and host + import ayon_api import pyblish.util + # Register target and host if not isinstance(path, str): raise RuntimeError("Path to JSON must be a string.") @@ -86,6 +87,19 @@ class Commands: log = Logger.get_logger("CLI-publish") + # Make public ayon api behave as other user + # - this works only if public ayon api is using service user + username = os.environ.get("AYON_USERNAME") + if username: + # NOTE: ayon-python-api does not have public api function to find + # out if is used service user. So we need to have try > except + # block. + con = ayon_api.get_server_api_connection() + try: + con.set_default_service_username(username) + except ValueError: + pass + install_ayon_plugins() manager = AddonsManager() diff --git a/client/ayon_core/hosts/__init__.py b/client/ayon_core/hosts/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/client/ayon_core/plugins/publish/collect_farm_target.py b/client/ayon_core/plugins/publish/collect_farm_target.py index 3bf89450ec..e0edd795d8 100644 --- a/client/ayon_core/plugins/publish/collect_farm_target.py +++ b/client/ayon_core/plugins/publish/collect_farm_target.py @@ -14,22 +14,20 @@ class CollectFarmTarget(pyblish.api.InstancePlugin): if not instance.data.get("farm"): return - context = instance.context + addons_manager = instance.context.data.get("ayonAddonsManager") - farm_name = "" - addons_manager = context.data.get("ayonAddonsManager") - - for farm_renderer in ["deadline", "royalrender"]: - addon = addons_manager.get(farm_renderer, False) - - if not addon: - self.log.error("Cannot find AYON addon '{0}'.".format( - farm_renderer)) - elif addon.enabled: + farm_renderer_addons = ["deadline", "royalrender"] + for farm_renderer in farm_renderer_addons: + addon = addons_manager.get(farm_renderer) + if addon and addon.enabled: farm_name = farm_renderer - - if farm_name: - self.log.debug("Collected render target: {0}".format(farm_name)) - instance.data["toBeRenderedOn"] = farm_name + break else: - AssertionError("No AYON renderer addon found") + # No enabled farm render addon found, then report all farm + # addons that were searched for yet not found + for farm_renderer in farm_renderer_addons: + self.log.error(f"Cannot find AYON addon '{farm_renderer}'.") + raise RuntimeError("No AYON renderer addon found.") + + self.log.debug("Collected render target: {0}".format(farm_name)) + instance.data["toBeRenderedOn"] = farm_name diff --git a/client/ayon_core/plugins/publish/integrate.py b/client/ayon_core/plugins/publish/integrate.py index 865b566e6e..1a4cda4dbb 100644 --- a/client/ayon_core/plugins/publish/integrate.py +++ b/client/ayon_core/plugins/publish/integrate.py @@ -380,29 +380,28 @@ class IntegrateAsset(pyblish.api.InstancePlugin): data = { "families": get_instance_families(instance) } - attribibutes = {} + attributes = {} product_group = instance.data.get("productGroup") if product_group: - attribibutes["productGroup"] = product_group + attributes["productGroup"] = product_group elif existing_product_entity: # Preserve previous product group if new version does not set it product_group = existing_product_entity.get("attrib", {}).get( "productGroup" ) if product_group is not None: - attribibutes["productGroup"] = product_group + attributes["productGroup"] = product_group product_id = None if existing_product_entity: product_id = existing_product_entity["id"] - product_entity = new_product_entity( product_name, product_type, folder_entity["id"], data=data, - attribs=attribibutes, + attribs=attributes, entity_id=product_id ) @@ -464,6 +463,7 @@ class IntegrateAsset(pyblish.api.InstancePlugin): version_number, product_entity["id"], task_id=task_id, + status=instance.data.get("status"), data=version_data, attribs=version_attributes, entity_id=version_id, diff --git a/client/pyproject.toml b/client/pyproject.toml index 72e5dd2794..ca88a37125 100644 --- a/client/pyproject.toml +++ b/client/pyproject.toml @@ -17,3 +17,4 @@ Click = "^8" OpenTimelineIO = "0.16.0" opencolorio = "2.2.1" Pillow = "9.5.0" +websocket-client = ">=0.40.0,<2" diff --git a/server_addon/max/client/ayon_max/api/pipeline.py b/server_addon/max/client/ayon_max/api/pipeline.py index 5f5e896e86..a87cd657ce 100644 --- a/server_addon/max/client/ayon_max/api/pipeline.py +++ b/server_addon/max/client/ayon_max/api/pipeline.py @@ -145,7 +145,27 @@ attributes "OpenPypeContext" rt.saveMaxFile(dst_path) -def ls() -> list: +def parse_container(container): + """Return the container node's full container data. + + Args: + container (str): A container node name. + + Returns: + dict: The container schema data for this container node. + + """ + data = lib.read(container) + + # Backwards compatibility pre-schemas for containers + data["schema"] = data.get("schema", "openpype:container-3.0") + + # Append transient data + data["objectName"] = container.Name + return data + + +def ls(): """Get all AYON containers.""" objs = rt.objects containers = [ @@ -156,7 +176,7 @@ def ls() -> list: ] for container in sorted(containers, key=attrgetter("name")): - yield lib.read(container) + yield parse_container(container) def on_new():