diff --git a/openpype/hooks/pre_global_host_data.py b/openpype/hooks/pre_global_host_data.py index bae967e25f..4c85a511ed 100644 --- a/openpype/hooks/pre_global_host_data.py +++ b/openpype/hooks/pre_global_host_data.py @@ -2,7 +2,7 @@ from openpype.api import Anatomy from openpype.lib import ( PreLaunchHook, EnvironmentPrepData, - prepare_host_environments, + prepare_app_environments, prepare_context_environments ) @@ -14,14 +14,6 @@ class GlobalHostDataHook(PreLaunchHook): def execute(self): """Prepare global objects to `data` that will be used for sure.""" - if not self.application.is_host: - self.log.info( - "Skipped hook {}. Application is not marked as host.".format( - self.__class__.__name__ - ) - ) - return - self.prepare_global_data() if not self.data.get("asset_doc"): @@ -49,7 +41,7 @@ class GlobalHostDataHook(PreLaunchHook): "log": self.log }) - prepare_host_environments(temp_data, self.launch_context.env_group) + prepare_app_environments(temp_data, self.launch_context.env_group) prepare_context_environments(temp_data) temp_data.pop("log") diff --git a/openpype/hosts/resolve/api/utils.py b/openpype/hosts/resolve/api/utils.py index 3dee17cb01..9b3762f328 100644 --- a/openpype/hosts/resolve/api/utils.py +++ b/openpype/hosts/resolve/api/utils.py @@ -70,9 +70,9 @@ def get_resolve_module(): sys.exit() # assign global var and return bmdvr = bmd.scriptapp("Resolve") - # bmdvf = bmd.scriptapp("Fusion") + bmdvf = bmd.scriptapp("Fusion") resolve.api.bmdvr = bmdvr - resolve.api.bmdvf = bmdvr.Fusion() + resolve.api.bmdvf = bmdvf log.info(("Assigning resolve module to " f"`pype.hosts.resolve.api.bmdvr`: {resolve.api.bmdvr}")) log.info(("Assigning resolve module to " diff --git a/openpype/lib/__init__.py b/openpype/lib/__init__.py index ebe7648ad7..f79c03ed57 100644 --- a/openpype/lib/__init__.py +++ b/openpype/lib/__init__.py @@ -130,7 +130,7 @@ from .applications import ( PostLaunchHook, EnvironmentPrepData, - prepare_host_environments, + prepare_app_environments, prepare_context_environments, get_app_environments_for_context, apply_project_environments_value @@ -261,7 +261,7 @@ __all__ = [ "PreLaunchHook", "PostLaunchHook", "EnvironmentPrepData", - "prepare_host_environments", + "prepare_app_environments", "prepare_context_environments", "get_app_environments_for_context", "apply_project_environments_value", diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index 393c83e9be..0b51a6629c 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -1295,7 +1295,7 @@ def get_app_environments_for_context( "env": env }) - prepare_host_environments(data, env_group) + prepare_app_environments(data, env_group) prepare_context_environments(data, env_group) # Discard avalon connection @@ -1316,7 +1316,7 @@ def _merge_env(env, current_env): return result -def prepare_host_environments(data, env_group=None, implementation_envs=True): +def prepare_app_environments(data, env_group=None, implementation_envs=True): """Modify launch environments based on launched app and context. Args: @@ -1474,6 +1474,22 @@ def prepare_context_environments(data, env_group=None): ) app = data["app"] + context_env = { + "AVALON_PROJECT": project_doc["name"], + "AVALON_ASSET": asset_doc["name"], + "AVALON_TASK": task_name, + "AVALON_APP_NAME": app.full_name + } + + log.debug( + "Context environments set:\n{}".format( + json.dumps(context_env, indent=4) + ) + ) + data["env"].update(context_env) + if not app.is_host: + return + workdir_data = get_workdir_data( project_doc, asset_doc, task_name, app.host_name ) @@ -1504,20 +1520,8 @@ def prepare_context_environments(data, env_group=None): "Couldn't create workdir because: {}".format(str(exc)) ) - context_env = { - "AVALON_PROJECT": project_doc["name"], - "AVALON_ASSET": asset_doc["name"], - "AVALON_TASK": task_name, - "AVALON_APP": app.host_name, - "AVALON_APP_NAME": app.full_name, - "AVALON_WORKDIR": workdir - } - log.debug( - "Context environments set:\n{}".format( - json.dumps(context_env, indent=4) - ) - ) - data["env"].update(context_env) + data["env"]["AVALON_APP"] = app.host_name + data["env"]["AVALON_WORKDIR"] = workdir _prepare_last_workfile(data, workdir) diff --git a/openpype/modules/ftrack/event_handlers_user/action_delete_asset.py b/openpype/modules/ftrack/event_handlers_user/action_delete_asset.py index 676dd80e93..94385a36c5 100644 --- a/openpype/modules/ftrack/event_handlers_user/action_delete_asset.py +++ b/openpype/modules/ftrack/event_handlers_user/action_delete_asset.py @@ -3,8 +3,9 @@ import uuid from datetime import datetime from bson.objectid import ObjectId -from openpype_modules.ftrack.lib import BaseAction, statics_icon from avalon.api import AvalonMongoDB +from openpype_modules.ftrack.lib import BaseAction, statics_icon +from openpype_modules.ftrack.lib.avalon_sync import create_chunks class DeleteAssetSubset(BaseAction): @@ -554,8 +555,8 @@ class DeleteAssetSubset(BaseAction): ftrack_proc_txt, ", ".join(ftrack_ids_to_delete) )) - entities_by_link_len = ( - self._filter_entities_to_delete(ftrack_ids_to_delete, session) + entities_by_link_len = self._prepare_entities_before_delete( + ftrack_ids_to_delete, session ) for link_len in sorted(entities_by_link_len.keys(), reverse=True): for entity in entities_by_link_len[link_len]: @@ -609,7 +610,7 @@ class DeleteAssetSubset(BaseAction): return self.report_handle(report_messages, project_name, event) - def _filter_entities_to_delete(self, ftrack_ids_to_delete, session): + def _prepare_entities_before_delete(self, ftrack_ids_to_delete, session): """Filter children entities to avoid CircularDependencyError.""" joined_ids_to_delete = ", ".join( ["\"{}\"".format(id) for id in ftrack_ids_to_delete] @@ -638,6 +639,21 @@ class DeleteAssetSubset(BaseAction): parent_ids_to_delete.append(entity["id"]) to_delete_entities.append(entity) + # Unset 'task_id' from AssetVersion entities + # - when task is deleted the asset version is not marked for deletion + task_ids = set( + entity["id"] + for entity in to_delete_entities + if entity.entity_type.lower() == "task" + ) + for chunk in create_chunks(task_ids): + asset_versions = session.query(( + "select id, task_id from AssetVersion where task_id in ({})" + ).format(self.join_query_keys(chunk))).all() + for asset_version in asset_versions: + asset_version["task_id"] = None + session.commit() + entities_by_link_len = collections.defaultdict(list) for entity in to_delete_entities: entities_by_link_len[len(entity["link"])].append(entity) diff --git a/openpype/modules/ftrack/lib/avalon_sync.py b/openpype/modules/ftrack/lib/avalon_sync.py index 06e8784287..db7c592c9b 100644 --- a/openpype/modules/ftrack/lib/avalon_sync.py +++ b/openpype/modules/ftrack/lib/avalon_sync.py @@ -33,6 +33,30 @@ CURRENT_DOC_SCHEMAS = { } +def create_chunks(iterable, chunk_size=None): + """Separate iterable into multiple chunks by size. + + Args: + iterable(list|tuple|set): Object that will be separated into chunks. + chunk_size(int): Size of one chunk. Default value is 200. + + Returns: + list: Chunked items. + """ + chunks = [] + if not iterable: + return chunks + + tupled_iterable = tuple(iterable) + iterable_size = len(tupled_iterable) + if chunk_size is None: + chunk_size = 200 + + for idx in range(0, iterable_size, chunk_size): + chunks.append(tupled_iterable[idx:idx + chunk_size]) + return chunks + + def check_regex(name, entity_type, in_schema=None, schema_patterns=None): schema_name = "asset-3.0" if in_schema: @@ -1147,10 +1171,8 @@ class SyncEntitiesFactory: ids_len = len(tupled_ids) chunk_size = int(5000 / ids_len) all_links = [] - for idx in range(0, ids_len, chunk_size): - entity_ids_joined = join_query_keys( - tupled_ids[idx:idx + chunk_size] - ) + for chunk in create_chunks(ftrack_ids, chunk_size): + entity_ids_joined = join_query_keys(chunk) all_links.extend(self.session.query(( "select from_id, to_id from" diff --git a/website/docs/module_deadline.md b/website/docs/module_deadline.md index 6b39f0780a..c96da91909 100644 --- a/website/docs/module_deadline.md +++ b/website/docs/module_deadline.md @@ -12,11 +12,11 @@ import TabItem from '@theme/TabItem'; For [AWS Thinkbox Deadline](https://www.awsthinkbox.com/deadline) support you need to set a few things up in both OpenPype and Deadline itself -1. Deploy OpenPype executable to all nodes of Deadline farm. See [Install & Run](admin_use). +1. Deploy OpenPype executable to all nodes of Deadline farm. See [Install & Run](admin_use.md) 2. Enable Deadline Module in the [OpenPype Admin Settings](admin_settings_system.md#deadline). -3. Set up *Deadline Web API service*. For more details on how to do it, see [here](https://docs.thinkboxsoftware.com/products/deadline/10.0/1_User%20Manual/manual/web-service.html). +3. Set up *Deadline Web API service*. For more details on how to do it, see [here](https://docs.thinkboxsoftware.com/products/deadline/10.1/1_User%20Manual/manual/web-service.html). 4. Point OpenPype to your deadline webservice URL in the [OpenPype Admin Settings](admin_settings_system.md#deadline).