From 03f631829b0096fa94640944201311ef118aa44d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Dec 2020 14:16:46 +0100 Subject: [PATCH 01/24] event filtering is separated method --- .../events/event_version_to_task_statuses.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index 0ea72be1cb..8e10bbd345 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -3,11 +3,9 @@ from pype.api import get_project_settings class VersionToTaskStatus(BaseEvent): - def launch(self, session, event): - '''Propagates status from version to task when changed''' - - # start of event procedure ---------------------------------- - for entity in event['data'].get('entities', []): + def filter_entity_info(self, event): + filtered_entity_info = [] + for entity in event["data"].get("entities", []): # Filter AssetVersions if entity["entityType"] != "assetversion": continue @@ -26,7 +24,16 @@ class VersionToTaskStatus(BaseEvent): ) # Just check that `new` is set to any value - if not version_status_id: + if version_status_id: + filtered_entity_info.append(filtered_entity_info) + return filtered_entity_info + + def launch(self, session, event): + '''Propagates status from version to task when changed''' + + filtered_entities_info = self.filter_entity_info(event) + if not filtered_entities_info: + return continue try: From c110ed9aa07da2a4e41b350da071268c1af0d848 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Dec 2020 14:17:49 +0100 Subject: [PATCH 02/24] query asset versions at once --- .../events/event_version_to_task_statuses.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index 8e10bbd345..df52595979 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -34,7 +34,33 @@ class VersionToTaskStatus(BaseEvent): filtered_entities_info = self.filter_entity_info(event) if not filtered_entities_info: return + + # Collect entity ids + asset_version_ids = set() + for entity_info in filtered_entities_info: + asset_version_ids.add(entity_info["entityId"]) + + # Query tasks for AssetVersions + asset_version_entities = session.query( + "AsserVersion where task_id != none and id in ({})".format( + self.join_query_keys(asset_version_ids) + ) + ).all() + if not asset_version_entities: + return + + asset_versions_by_id = { + asset_version["id"]: asset_version + for asset_version in asset_version_entities + } + + # Query status entities + status_ids = set() + for entity_info in filtered_entities_info: + # Skip statuses of asset versions without task + if entity_info["entityId"] not in asset_versions_by_id: continue + status_ids.add(entity_info["changes"]["statusid"]["new"]) try: version_status = session.get("Status", version_status_id) From 3a24a38afb42cbc8a106bceaebfcd9f6b4d06793 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Dec 2020 14:18:04 +0100 Subject: [PATCH 03/24] implemented `join_query_keys` --- .../modules/ftrack/events/event_version_to_task_statuses.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index df52595979..761890e505 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -3,6 +3,12 @@ from pype.api import get_project_settings class VersionToTaskStatus(BaseEvent): + # TODO remove `join_query_keys` as it should be in `BaseHandler` + @staticmethod + def join_query_keys(keys): + """Helper to join keys to query.""" + return ",".join(["\"{}\"".format(key) for key in keys]) + def filter_entity_info(self, event): filtered_entity_info = [] for entity in event["data"].get("entities", []): From ef4d395ea7eee4bfc3c416d5866eef297b9ebe90 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Dec 2020 14:59:30 +0100 Subject: [PATCH 04/24] filter asset versions by asset type --- .../events/event_version_to_task_statuses.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index 761890e505..36c54edac5 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -47,14 +47,26 @@ class VersionToTaskStatus(BaseEvent): asset_version_ids.add(entity_info["entityId"]) # Query tasks for AssetVersions - asset_version_entities = session.query( + _asset_version_entities = session.query( "AsserVersion where task_id != none and id in ({})".format( self.join_query_keys(asset_version_ids) ) ).all() - if not asset_version_entities: + if not _asset_version_entities: return + # Filter asset versions by asset type and store their task_ids + task_ids = set() + asset_version_entities = [] + for asset_version in _asset_version_entities: + if asset_version["asset"]["type"]["short"].lower() == "scene": + continue + asset_version_entities.append(asset_version) + task_ids.add(asset_version["task_id"]) + + # Skipt if `task_ids` are empty + if not task_ids: + return asset_versions_by_id = { asset_version["id"]: asset_version for asset_version in asset_version_entities From 36f656c498409fb2d9bbf6369b8ab463cddfd127 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Dec 2020 14:59:47 +0100 Subject: [PATCH 05/24] method for preparing project specific data --- .../events/event_version_to_task_statuses.py | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index 36c54edac5..9bf4bc11bd 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -34,6 +34,57 @@ class VersionToTaskStatus(BaseEvent): filtered_entity_info.append(filtered_entity_info) return filtered_entity_info + def prepare_project_data(self, session, event, task_entities): + output = { + "status_mapping": None, + "task_statuses": None + } + + # Try to get project entity from event + project_entity = event["data"].get("project_entity") + if not project_entity: + # Get project entity from task and store to event + project_entity = self.get_project_from_entity(task_entities[0]) + event["data"]["project_entity"] = project_entity + + project_name = project_entity["full_name"] + project_settings = get_project_settings(project_name) + + # Load status mapping from presets + event_settings = ( + project_settings["ftrack"]["events"]["status_version_to_task"] + ) + # Skip if event is not enabled or status mapping is not set + if not event_settings["enabled"]: + self.log.debug("Project \"{}\" has disabled {}".format( + project_name, self.__class__.__name__ + )) + return output + + status_mapping = event_settings["mapping"] + if not status_mapping: + self.log.debug( + "Project \"{}\" does not have set mapping for {}".format( + project_name, self.__class__.__name__ + ) + ) + return output + + # Store status mapping to output + output["status_mapping"] = status_mapping + + task_object_type = session.query( + "ObjectType where name is \"Task\"" + ).one() + + project_schema = project_entity["project_schema"] + # Get all available statuses for Task and store to output + output["task_statuses"] = list(project_schema.get_statuses( + "Task", task_object_type["id"] + )) + + return output + def launch(self, session, event): '''Propagates status from version to task when changed''' From fcdb50c44f481f0406ae8e5258d981de3a58584c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Dec 2020 15:00:28 +0100 Subject: [PATCH 06/24] prepare all data before real processing to not get there all the time --- .../events/event_version_to_task_statuses.py | 107 ++++++++++-------- 1 file changed, 57 insertions(+), 50 deletions(-) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index 9bf4bc11bd..6486168e5c 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -118,11 +118,41 @@ class VersionToTaskStatus(BaseEvent): # Skipt if `task_ids` are empty if not task_ids: return + + task_entities = session.query( + "select project_id from Task where id in ({})".format( + self.join_query_keys(task_ids) + ) + ).all() + task_entities_by_id = { + task_entiy["id"]: task_entiy + for task_entiy in task_entities + } + project_data = self.prepare_project_data( + session, event, task_entities + ) + + if ( + not project_data["status_mapping"] + or not project_data["task_statuses"] + ): + return + + # Prepare asset version by their id asset_versions_by_id = { asset_version["id"]: asset_version for asset_version in asset_version_entities } + status_mapping = project_data["status_mapping"] + task_statuses = project_data["task_statuses"] + + # map lowered status name with it's object + task_statuses_by_low_name = { + status["name"].lower(): status + for status in task_statuses + } + # Query status entities status_ids = set() for entity_info in filtered_entities_info: @@ -131,74 +161,49 @@ class VersionToTaskStatus(BaseEvent): continue status_ids.add(entity_info["changes"]["statusid"]["new"]) - try: - version_status = session.get("Status", version_status_id) - except Exception: - self.log.warning( - "Troubles with query status id [ {} ]".format( - version_status_id - ), - exc_info=True - ) - - if not version_status: - continue - - version_status_orig = version_status["name"] - - # Get entities necessary for processing - version = session.get("AssetVersion", entity["entityId"]) - task = version.get("task") - if not task: - continue - - project_entity = self.get_project_from_entity(task) - project_name = project_entity["full_name"] - project_settings = get_project_settings(project_name) - - # Load status mapping from presets - status_mapping = ( - project_settings["ftrack"]["events"]["status_version_to_task"]) - # Skip if mapping is empty - if not status_mapping: + # Qeury statuses + status_entities = session.query( + "select id, name from Status where id in ({})".format( + self.join_query_keys(status_ids) + ) + ).all() + # Prepare status names by their ids + status_name_by_id = { + status_entity["id"]: status_entity["name"] + for status_entity in status_entities + } + for entity_info in filtered_entities_info: + entity_id = entity_info["entityId"] + status_id = entity_info["changes"]["statusid"]["new"] + status_name = status_name_by_id.get(status_id) + status_name_low = status_name.lower() + if not status_name_low: continue # Lower version status name and check if has mapping - version_status = version_status_orig.lower() new_status_names = [] - mapped = status_mapping.get(version_status) + mapped = status_mapping.get(status_name_low) if mapped: new_status_names.extend(list(mapped)) - new_status_names.append(version_status) + new_status_names.append(status_name_low) self.log.debug( "Processing AssetVersion status change: [ {} ]".format( - version_status_orig + status_name ) ) # Lower all names from presets new_status_names = [name.lower() for name in new_status_names] - if version["asset"]["type"]["short"].lower() == "scene": - continue - - project_schema = project_entity["project_schema"] - # Get all available statuses for Task - statuses = project_schema.get_statuses("Task", task["type_id"]) - # map lowered status name with it's object - stat_names_low = { - status["name"].lower(): status for status in statuses - } - new_status = None for status_name in new_status_names: - if status_name not in stat_names_low: + if status_name not in task_statuses_by_low_name: continue # store object of found status - new_status = stat_names_low[status_name] + new_status = task_statuses_by_low_name[status_name] self.log.debug("Status to set: [ {} ]".format( new_status["name"] )) @@ -213,15 +218,17 @@ class VersionToTaskStatus(BaseEvent): ) continue + asset_version = asset_versions_by_id[entity_id] + task_entity = task_entities_by_id[asset_version["task_id"]] # Get full path to task for logging - ent_path = "/".join([ent["name"] for ent in task["link"]]) + ent_path = "/".join([ent["name"] for ent in task_entity["link"]]) # Setting task status try: - task["status"] = new_status + task_entity["status"] = new_status session.commit() self.log.debug("[ {} ] Status updated to [ {} ]".format( - ent_path, new_status['name'] + ent_path, new_status["name"] )) except Exception: session.rollback() From f1b7bd1f7c11557576bd481a892754f2a22bae1c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Dec 2020 15:32:47 +0100 Subject: [PATCH 07/24] store filtered info by project id --- .../events/event_version_to_task_statuses.py | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index 6486168e5c..6d0dd4cfc5 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -10,28 +10,34 @@ class VersionToTaskStatus(BaseEvent): return ",".join(["\"{}\"".format(key) for key in keys]) def filter_entity_info(self, event): - filtered_entity_info = [] - for entity in event["data"].get("entities", []): + filtered_entity_info = {} + for entity_info in event["data"].get("entities", []): # Filter AssetVersions - if entity["entityType"] != "assetversion": + if entity_info["entityType"] != "assetversion": continue # Skip if statusid not in keys (in changes) - keys = entity.get("keys") + keys = entity_info.get("keys") if not keys or "statusid" not in keys: continue # Get new version task name version_status_id = ( - entity + entity_info .get("changes", {}) .get("statusid", {}) .get("new", {}) ) # Just check that `new` is set to any value - if version_status_id: - filtered_entity_info.append(filtered_entity_info) + if not version_status_id: + continue + + # Get project id from entity info + project_id = entity_info["parents"][-1]["entityId"] + if project_id not in filtered_entity_info: + filtered_entity_info[project_id] = [] + filtered_entity_info[project_id].append(filtered_entity_info) return filtered_entity_info def prepare_project_data(self, session, event, task_entities): From 365b61fceaec042afcfdf44b88cc440dc5ff56e3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Dec 2020 15:33:37 +0100 Subject: [PATCH 08/24] `launch` renamed to `process_by_project` which is triggered by new `launch` --- .../events/event_version_to_task_statuses.py | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index 6d0dd4cfc5..691ffac468 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -3,6 +3,18 @@ from pype.api import get_project_settings class VersionToTaskStatus(BaseEvent): + """Propagates status from version to task when changed.""" + def launch(self, session, event): + # Filter event entities + # - output is dictionary where key is project id and event info in + # value + filtered_entities_info = self.filter_entity_info(event) + if not filtered_entities_info: + return + + for project_id, entities_info in filtered_entities_info.items(): + self.process_by_project(session, project_id, entities_info) + # TODO remove `join_query_keys` as it should be in `BaseHandler` @staticmethod def join_query_keys(keys): @@ -91,13 +103,7 @@ class VersionToTaskStatus(BaseEvent): return output - def launch(self, session, event): - '''Propagates status from version to task when changed''' - - filtered_entities_info = self.filter_entity_info(event) - if not filtered_entities_info: - return - + def process_by_project(self, session, project_id, entities_info): # Collect entity ids asset_version_ids = set() for entity_info in filtered_entities_info: From de4aac7bb24bd26f0e289678f396bca39588daf3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Dec 2020 15:34:05 +0100 Subject: [PATCH 09/24] project data are prepared by project id --- .../events/event_version_to_task_statuses.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index 691ffac468..06c963d41b 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -52,18 +52,23 @@ class VersionToTaskStatus(BaseEvent): filtered_entity_info[project_id].append(filtered_entity_info) return filtered_entity_info - def prepare_project_data(self, session, event, task_entities): + def prepare_project_data(self, session, event, project_id): output = { "status_mapping": None, "task_statuses": None } # Try to get project entity from event - project_entity = event["data"].get("project_entity") + project_entities = event["data"].get("project_entities") + if not project_entities: + project_entities = {} + event["data"]["project_entities"] = project_entities + + project_entity = project_entities.get(project_id) if not project_entity: # Get project entity from task and store to event - project_entity = self.get_project_from_entity(task_entities[0]) - event["data"]["project_entity"] = project_entity + project_entity = session.get("Project", project_id) + event["data"]["project_entities"][project_id] = project_entity project_name = project_entity["full_name"] project_settings = get_project_settings(project_name) @@ -140,9 +145,7 @@ class VersionToTaskStatus(BaseEvent): task_entiy["id"]: task_entiy for task_entiy in task_entities } - project_data = self.prepare_project_data( - session, event, task_entities - ) + project_data = self.prepare_project_data(session, event, project_id) if ( not project_data["status_mapping"] From a76f3e04cc76d5e7491653d520092edb5053bb9a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Dec 2020 15:34:13 +0100 Subject: [PATCH 10/24] changed task query --- pype/modules/ftrack/events/event_version_to_task_statuses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index 06c963d41b..74565c3a3b 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -137,7 +137,7 @@ class VersionToTaskStatus(BaseEvent): return task_entities = session.query( - "select project_id from Task where id in ({})".format( + "select link from Task where id in ({})".format( self.join_query_keys(task_ids) ) ).all() From ee3beee57f39e16a9f4ae3576d221156b729002a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Dec 2020 15:58:53 +0100 Subject: [PATCH 11/24] finishing touches --- .../events/event_version_to_task_statuses.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index 74565c3a3b..5b9835be0b 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -13,7 +13,7 @@ class VersionToTaskStatus(BaseEvent): return for project_id, entities_info in filtered_entities_info.items(): - self.process_by_project(session, project_id, entities_info) + self.process_by_project(session, event, project_id, entities_info) # TODO remove `join_query_keys` as it should be in `BaseHandler` @staticmethod @@ -49,7 +49,7 @@ class VersionToTaskStatus(BaseEvent): project_id = entity_info["parents"][-1]["entityId"] if project_id not in filtered_entity_info: filtered_entity_info[project_id] = [] - filtered_entity_info[project_id].append(filtered_entity_info) + filtered_entity_info[project_id].append(entity_info) return filtered_entity_info def prepare_project_data(self, session, event, project_id): @@ -108,15 +108,15 @@ class VersionToTaskStatus(BaseEvent): return output - def process_by_project(self, session, project_id, entities_info): + def process_by_project(self, session, event, project_id, entities_info): # Collect entity ids asset_version_ids = set() - for entity_info in filtered_entities_info: + for entity_info in entities_info: asset_version_ids.add(entity_info["entityId"]) # Query tasks for AssetVersions _asset_version_entities = session.query( - "AsserVersion where task_id != none and id in ({})".format( + "AssetVersion where task_id != none and id in ({})".format( self.join_query_keys(asset_version_ids) ) ).all() @@ -170,7 +170,7 @@ class VersionToTaskStatus(BaseEvent): # Query status entities status_ids = set() - for entity_info in filtered_entities_info: + for entity_info in entities_info: # Skip statuses of asset versions without task if entity_info["entityId"] not in asset_versions_by_id: continue @@ -187,7 +187,7 @@ class VersionToTaskStatus(BaseEvent): status_entity["id"]: status_entity["name"] for status_entity in status_entities } - for entity_info in filtered_entities_info: + for entity_info in entities_info: entity_id = entity_info["entityId"] status_id = entity_info["changes"]["statusid"]["new"] status_name = status_name_by_id.get(status_id) From aadec6f48dacf42ce9610474671889748fc83923 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Dec 2020 15:59:57 +0100 Subject: [PATCH 12/24] fixed few imports --- pype/modules/ftrack/ftrack_server/event_server_cli.py | 2 +- pype/modules/ftrack/ftrack_server/ftrack_server.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pype/modules/ftrack/ftrack_server/event_server_cli.py b/pype/modules/ftrack/ftrack_server/event_server_cli.py index dbf2a2dc10..96581f0a38 100644 --- a/pype/modules/ftrack/ftrack_server/event_server_cli.py +++ b/pype/modules/ftrack/ftrack_server/event_server_cli.py @@ -23,7 +23,7 @@ from pype.modules.ftrack.ftrack_server.lib import ( get_ftrack_event_mongo_info ) -import socket_thread +from pype.modules.ftrack.ftrack_server import socket_thread class MongoPermissionsError(Exception): diff --git a/pype/modules/ftrack/ftrack_server/ftrack_server.py b/pype/modules/ftrack/ftrack_server/ftrack_server.py index af48bfadc8..93c7cd3a67 100644 --- a/pype/modules/ftrack/ftrack_server/ftrack_server.py +++ b/pype/modules/ftrack/ftrack_server/ftrack_server.py @@ -8,10 +8,10 @@ import inspect import ftrack_api -from pype.api import Logger +from pype.lib import PypeLogger -log = Logger().get_logger(__name__) +log = PypeLogger().get_logger(__name__) """ # Required - Needed for connection to Ftrack From 0669b3386d73a8c966cb8d28fe601307d767da00 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Dec 2020 16:01:40 +0100 Subject: [PATCH 13/24] added (at least) previous event server launch way --- pype/pype_commands.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pype/pype_commands.py b/pype/pype_commands.py index cc54deb2ee..f504728ca1 100644 --- a/pype/pype_commands.py +++ b/pype/pype_commands.py @@ -60,7 +60,18 @@ class PypeCommands: return return_code def launch_eventservercli(self, args): - pass + from pype.modules import ftrack + from pype.lib import execute + + fname = os.path.join( + os.path.dirname(os.path.abspath(ftrack.__file__)), + "ftrack_server", + "event_server_cli.py" + ) + + return execute([ + sys.executable, "-u", fname + ]) def publish(self, gui, paths): pass From ddd4268d3725ae2705a831d23e68be2df25a4605 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Dec 2020 16:09:01 +0100 Subject: [PATCH 14/24] store project settings to event data --- .../ftrack/events/event_version_to_task_statuses.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index 5b9835be0b..d7a1dad31a 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -71,7 +71,16 @@ class VersionToTaskStatus(BaseEvent): event["data"]["project_entities"][project_id] = project_entity project_name = project_entity["full_name"] - project_settings = get_project_settings(project_name) + + project_settings_by_id = event["data"].get("project_settings") + if not project_settings_by_id: + project_settings_by_id = {} + event["data"]["project_settings"] = project_settings_by_id + + project_settings = project_settings_by_id.get(project_name) + if not project_settings: + project_settings = get_project_settings(project_name) + event["data"]["project_settings"][project_name] = project_settings # Load status mapping from presets event_settings = ( From 6a5559c9b23c370dca9bd2c12b847b0cdeb2458c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Dec 2020 17:17:01 +0100 Subject: [PATCH 15/24] loading project settings is part of BaseHandler as it will be used across events --- .../events/event_version_to_task_statuses.py | 29 ++------ .../modules/ftrack/lib/ftrack_base_handler.py | 66 +++++++++++++++++++ 2 files changed, 72 insertions(+), 23 deletions(-) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index d7a1dad31a..f155108d7f 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -57,31 +57,14 @@ class VersionToTaskStatus(BaseEvent): "status_mapping": None, "task_statuses": None } - - # Try to get project entity from event - project_entities = event["data"].get("project_entities") - if not project_entities: - project_entities = {} - event["data"]["project_entities"] = project_entities - - project_entity = project_entities.get(project_id) - if not project_entity: - # Get project entity from task and store to event - project_entity = session.get("Project", project_id) - event["data"]["project_entities"][project_id] = project_entity + project_entity = self.get_project_entity_from_event( + session, event, project_id + ) + project_settings = self.get_settings_for_project( + session, event, project_entity=project_entity + ) project_name = project_entity["full_name"] - - project_settings_by_id = event["data"].get("project_settings") - if not project_settings_by_id: - project_settings_by_id = {} - event["data"]["project_settings"] = project_settings_by_id - - project_settings = project_settings_by_id.get(project_name) - if not project_settings: - project_settings = get_project_settings(project_name) - event["data"]["project_settings"][project_name] = project_settings - # Load status mapping from presets event_settings = ( project_settings["ftrack"]["events"]["status_version_to_task"] diff --git a/pype/modules/ftrack/lib/ftrack_base_handler.py b/pype/modules/ftrack/lib/ftrack_base_handler.py index e928f2fb88..669381af90 100644 --- a/pype/modules/ftrack/lib/ftrack_base_handler.py +++ b/pype/modules/ftrack/lib/ftrack_base_handler.py @@ -1,6 +1,8 @@ import functools import time from pype.api import Logger +from pype.settings import get_project_settings + import ftrack_api from pype.modules.ftrack import ftrack_server @@ -581,3 +583,67 @@ class BaseHandler(object): return self.session.query( "Project where id is {}".format(project_data["id"]) ).one() + + def get_project_entity_from_event(self, session, event, project_id): + """Load or query and fill project entity from/to event data. + + Project data are stored by ftrack id because in most cases it is + easier to access project id than project name. + + Args: + session (ftrack_api.Session): Current session. + event (ftrack_api.Event): Processed event by session. + project_id (str): Ftrack project id. + """ + if not project_id: + raise ValueError( + "Entered `project_id` is not valid. {} ({})".format( + str(project_id), str(type(project_id)) + ) + ) + # Try to get project entity from event + project_entities = event["data"].get("project_entities") + if not project_entities: + project_entities = {} + event["data"]["project_entities"] = project_entities + + project_entity = project_entities.get(project_id) + if not project_entity: + # Get project entity from task and store to event + project_entity = session.get("Project", project_id) + event["data"]["project_entities"][project_id] = project_entity + return project_entity + + def get_settings_for_project( + self, session, event, project_id=None, project_entity=None + ): + """Load or fill pype's project settings from event data. + + Project data are stored by ftrack id because in most cases it is + easier to access project id than project name. + + Args: + session (ftrack_api.Session): Current session. + event (ftrack_api.Event): Processed event by session. + project_id (str): Ftrack project id. Must be entered if + project_entity is not. + project_entity (ftrack_api.Entity): Project entity. Must be entered + if project_id is not. + """ + if not project_entity: + project_entity = self.get_project_entity_from_event( + session, event, project_id + ) + + project_name = project_entity["full_name"] + + project_settings_by_id = event["data"].get("project_settings") + if not project_settings_by_id: + project_settings_by_id = {} + event["data"]["project_settings"] = project_settings_by_id + + project_settings = project_settings_by_id.get(project_id) + if not project_settings: + project_settings = get_project_settings(project_name) + event["data"]["project_settings"][project_id] = project_settings + return project_settings From 2198b60019fb9798225e31189490034d4ac15182 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Dec 2020 10:25:21 +0100 Subject: [PATCH 16/24] lower settings statuses --- .../events/event_version_to_task_statuses.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index f155108d7f..c5bbfaea8b 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -86,7 +86,10 @@ class VersionToTaskStatus(BaseEvent): return output # Store status mapping to output - output["status_mapping"] = status_mapping + output["status_mapping"] = { + key.lower(): value + for key, value in status_mapping.items() + } task_object_type = session.query( "ObjectType where name is \"Task\"" @@ -139,10 +142,9 @@ class VersionToTaskStatus(BaseEvent): } project_data = self.prepare_project_data(session, event, project_id) - if ( - not project_data["status_mapping"] - or not project_data["task_statuses"] - ): + status_mapping = project_data["status_mapping"] + task_statuses = project_data["task_statuses"] + if not status_mapping or not task_statuses: return # Prepare asset version by their id @@ -151,9 +153,6 @@ class VersionToTaskStatus(BaseEvent): for asset_version in asset_version_entities } - status_mapping = project_data["status_mapping"] - task_statuses = project_data["task_statuses"] - # map lowered status name with it's object task_statuses_by_low_name = { status["name"].lower(): status @@ -183,9 +182,9 @@ class VersionToTaskStatus(BaseEvent): entity_id = entity_info["entityId"] status_id = entity_info["changes"]["statusid"]["new"] status_name = status_name_by_id.get(status_id) - status_name_low = status_name.lower() - if not status_name_low: + if not status_name: continue + status_name_low = status_name.lower() # Lower version status name and check if has mapping new_status_names = [] From 3fe6704cb1cc32e7a4e06e0e17881404b36ad701 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Dec 2020 14:17:43 +0100 Subject: [PATCH 17/24] move loading of project data earlier --- .../ftrack/events/event_version_to_task_statuses.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index c5bbfaea8b..77fab47d3c 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -104,6 +104,13 @@ class VersionToTaskStatus(BaseEvent): return output def process_by_project(self, session, event, project_id, entities_info): + # Check for project data if event is enabled for event handler + project_data = self.prepare_project_data(session, event, project_id) + status_mapping = project_data["status_mapping"] + task_statuses = project_data["task_statuses"] + if not status_mapping or not task_statuses: + return + # Collect entity ids asset_version_ids = set() for entity_info in entities_info: @@ -140,12 +147,6 @@ class VersionToTaskStatus(BaseEvent): task_entiy["id"]: task_entiy for task_entiy in task_entities } - project_data = self.prepare_project_data(session, event, project_id) - - status_mapping = project_data["status_mapping"] - task_statuses = project_data["task_statuses"] - if not status_mapping or not task_statuses: - return # Prepare asset version by their id asset_versions_by_id = { From bc65526f94479d55c6bb17d22678e85e4c59b096 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Dec 2020 14:17:54 +0100 Subject: [PATCH 18/24] remove unused import --- pype/modules/ftrack/events/event_version_to_task_statuses.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index 77fab47d3c..c7c1394f1a 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -1,5 +1,4 @@ from pype.modules.ftrack import BaseEvent -from pype.api import get_project_settings class VersionToTaskStatus(BaseEvent): From 9e663a7c69009dbd234639741433e935dcfa0bf6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Dec 2020 15:24:11 +0100 Subject: [PATCH 19/24] removed prepare_project_data method --- .../events/event_version_to_task_statuses.py | 44 +++++-------------- 1 file changed, 10 insertions(+), 34 deletions(-) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index c7c1394f1a..5f994c6f1a 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -51,11 +51,9 @@ class VersionToTaskStatus(BaseEvent): filtered_entity_info[project_id].append(entity_info) return filtered_entity_info - def prepare_project_data(self, session, event, project_id): - output = { - "status_mapping": None, - "task_statuses": None - } + def process_by_project(self, session, event, project_id, entities_info): + # Check for project data if event is enabled for event handler + status_mapping = None project_entity = self.get_project_entity_from_event( session, event, project_id ) @@ -73,43 +71,21 @@ class VersionToTaskStatus(BaseEvent): self.log.debug("Project \"{}\" has disabled {}".format( project_name, self.__class__.__name__ )) - return output + return - status_mapping = event_settings["mapping"] - if not status_mapping: + _status_mapping = event_settings["mapping"] + if not _status_mapping: self.log.debug( "Project \"{}\" does not have set mapping for {}".format( project_name, self.__class__.__name__ ) ) - return output - - # Store status mapping to output - output["status_mapping"] = { - key.lower(): value - for key, value in status_mapping.items() - } - - task_object_type = session.query( - "ObjectType where name is \"Task\"" - ).one() - - project_schema = project_entity["project_schema"] - # Get all available statuses for Task and store to output - output["task_statuses"] = list(project_schema.get_statuses( - "Task", task_object_type["id"] - )) - - return output - - def process_by_project(self, session, event, project_id, entities_info): - # Check for project data if event is enabled for event handler - project_data = self.prepare_project_data(session, event, project_id) - status_mapping = project_data["status_mapping"] - task_statuses = project_data["task_statuses"] - if not status_mapping or not task_statuses: return + status_mapping = { + key.lower(): value + for key, value in _status_mapping.items() + } # Collect entity ids asset_version_ids = set() for entity_info in entities_info: From 503346e320f4cd84ea2dc31e9ca40eeaf2716586 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Dec 2020 15:24:43 +0100 Subject: [PATCH 20/24] task statuses are got for specific task types now --- .../events/event_version_to_task_statuses.py | 43 +++++++++++++------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index 5f994c6f1a..4e5a5f002d 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -129,12 +129,6 @@ class VersionToTaskStatus(BaseEvent): for asset_version in asset_version_entities } - # map lowered status name with it's object - task_statuses_by_low_name = { - status["name"].lower(): status - for status in task_statuses - } - # Query status entities status_ids = set() for entity_info in entities_info: @@ -143,16 +137,20 @@ class VersionToTaskStatus(BaseEvent): continue status_ids.add(entity_info["changes"]["statusid"]["new"]) - # Qeury statuses - status_entities = session.query( + version_status_entities = session.query( "select id, name from Status where id in ({})".format( self.join_query_keys(status_ids) ) ).all() + + # Qeury statuses + statusese_by_obj_id = self.statuses_for_tasks( + session, task_entities, project_entity + ) # Prepare status names by their ids status_name_by_id = { status_entity["id"]: status_entity["name"] - for status_entity in status_entities + for status_entity in version_status_entities } for entity_info in entities_info: entity_id = entity_info["entityId"] @@ -176,12 +174,20 @@ class VersionToTaskStatus(BaseEvent): ) ) + asset_version = asset_versions_by_id[entity_id] + task_entity = task_entities_by_id[asset_version["task_id"]] + type_id = task_entity["type_id"] + # Lower all names from presets new_status_names = [name.lower() for name in new_status_names] + task_statuses_by_low_name = statusese_by_obj_id[type_id] new_status = None for status_name in new_status_names: if status_name not in task_statuses_by_low_name: + self.log.debug(( + "Task does not have status name \"{}\" available." + ).format(status_name)) continue # store object of found status @@ -199,9 +205,6 @@ class VersionToTaskStatus(BaseEvent): ) ) continue - - asset_version = asset_versions_by_id[entity_id] - task_entity = task_entities_by_id[asset_version["task_id"]] # Get full path to task for logging ent_path = "/".join([ent["name"] for ent in task_entity["link"]]) @@ -219,6 +222,22 @@ class VersionToTaskStatus(BaseEvent): exc_info=True ) + def statuses_for_tasks(self, session, task_entities, project_entity): + task_type_ids = set() + for task_entity in task_entities: + task_type_ids.add(task_entity["type_id"]) + + project_schema = project_entity["project_schema"] + output = {} + for task_type_id in task_type_ids: + statuses = project_schema.get_statuses("Task", task_type_id) + output[task_type_id] = { + status["name"].lower(): status + for status in statuses + } + + return output + def register(session, plugins_presets): '''Register plugin. Called when used as an plugin.''' From 991ce7f91618809b54b2678e1cf456baaf200470 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Dec 2020 16:03:38 +0100 Subject: [PATCH 21/24] added label to Version to Task event in settings --- .../gui_schemas/projects_schema/schema_project_ftrack.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json index ea01400e94..5c76ba9e83 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json @@ -209,6 +209,10 @@ "key": "enabled", "label": "Enabled" }, + { + "type": "label", + "label": "Set Task status based on changed Asset Version status.
Version's new status on left side trigger to change task's status to first possible on right side.
- it is also tried to set version's status to task if none will match or will be available" + }, { "type": "dict-modifiable", "key": "mapping", From 87168f90f4dbc6510ffae9b6e5f8b5f04d9806af Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Dec 2020 16:12:13 +0100 Subject: [PATCH 22/24] added TODO --- pype/modules/ftrack/events/event_version_to_task_statuses.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index 4e5a5f002d..03dc2a0979 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -104,6 +104,7 @@ class VersionToTaskStatus(BaseEvent): task_ids = set() asset_version_entities = [] for asset_version in _asset_version_entities: + # TODO replace with settings if asset_version["asset"]["type"]["short"].lower() == "scene": continue asset_version_entities.append(asset_version) From a62116ec7176b460567c83a3c6e00f6620fd887f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Dec 2020 16:27:12 +0100 Subject: [PATCH 23/24] skipping asset types are loaded from settings --- .../events/event_version_to_task_statuses.py | 13 ++++-- .../defaults/project_settings/ftrack.json | 5 ++- .../schema_project_ftrack.json | 42 ++++++++++++------- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index 03dc2a0979..ed47d2f8a9 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -86,6 +86,12 @@ class VersionToTaskStatus(BaseEvent): key.lower(): value for key, value in _status_mapping.items() } + + asset_types_to_skip = [ + short_name.lower() + for short_name in event_settings["asset_types_to_skip"] + ] + # Collect entity ids asset_version_ids = set() for entity_info in entities_info: @@ -104,9 +110,10 @@ class VersionToTaskStatus(BaseEvent): task_ids = set() asset_version_entities = [] for asset_version in _asset_version_entities: - # TODO replace with settings - if asset_version["asset"]["type"]["short"].lower() == "scene": - continue + if asset_types_to_skip: + short_name = asset_version["asset"]["type"]["short"].lower() + if short_name in asset_types_to_skip: + continue asset_version_entities.append(asset_version) task_ids.add(asset_version["task_id"]) diff --git a/pype/settings/defaults/project_settings/ftrack.json b/pype/settings/defaults/project_settings/ftrack.json index 5481574ef8..a0cff06283 100644 --- a/pype/settings/defaults/project_settings/ftrack.json +++ b/pype/settings/defaults/project_settings/ftrack.json @@ -75,7 +75,10 @@ "Approved", "Complete" ] - } + }, + "asset_types_to_skip": [ + "scene" + ] }, "first_version_status": { "enabled": true, diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json index 5c76ba9e83..bd10c64457 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json @@ -204,24 +204,38 @@ "label": "Sync status from Version to Task", "checkbox_key": "enabled", "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "label", - "label": "Set Task status based on changed Asset Version status.
Version's new status on left side trigger to change task's status to first possible on right side.
- it is also tried to set version's status to task if none will match or will be available" - }, - { - "type": "dict-modifiable", - "key": "mapping", - "object_type": + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "label", + "label": "Set Task status based on changed Asset Version status.
Version's new status on left side trigger to change task's status to first possible on right side.
- it is also tried to set version's status to task if none will match or will be available" + }, + { + "type": "dict-modifiable", + "key": "mapping", + "object_type": + { + "type": "list", + "object_type": "text" + } + }, + { + "type": "separator" + }, + { + "type": "label", + "label": "Disable event if status was changed on specific Asset type." + }, { "type": "list", + "label": "Asset types (short)", + "key": "asset_types_to_skip", "object_type": "text" } - }] + ] }, { "type": "dict", From 86f27fd3f7442b0b7c369bb3c72014cbb825fc8d Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 16 Dec 2020 20:40:04 +0100 Subject: [PATCH 24/24] tweak the help text --- pype/settings/defaults/project_settings/ftrack.json | 3 +-- pype/settings/defaults/project_settings/global.json | 2 +- pype/settings/defaults/project_settings/maya.json | 3 ++- pype/settings/defaults/project_settings/nuke.json | 2 +- .../gui_schemas/projects_schema/schema_project_ftrack.json | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pype/settings/defaults/project_settings/ftrack.json b/pype/settings/defaults/project_settings/ftrack.json index a0cff06283..8a597c3e6a 100644 --- a/pype/settings/defaults/project_settings/ftrack.json +++ b/pype/settings/defaults/project_settings/ftrack.json @@ -71,8 +71,7 @@ "status_version_to_task": { "enabled": true, "mapping": { - "Complete": [ - "Approved", + "Approved": [ "Complete" ] }, diff --git a/pype/settings/defaults/project_settings/global.json b/pype/settings/defaults/project_settings/global.json index da56fd34e7..4e2b9fce81 100644 --- a/pype/settings/defaults/project_settings/global.json +++ b/pype/settings/defaults/project_settings/global.json @@ -179,4 +179,4 @@ } } } -} +} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/maya.json b/pype/settings/defaults/project_settings/maya.json index c779d495c4..b8c0dffa26 100644 --- a/pype/settings/defaults/project_settings/maya.json +++ b/pype/settings/defaults/project_settings/maya.json @@ -136,7 +136,8 @@ "enabled": false }, "ValidateAttributes": { - "enabled": false + "enabled": false, + "attributes": {} }, "ExtractCameraAlembic": { "enabled": true, diff --git a/pype/settings/defaults/project_settings/nuke.json b/pype/settings/defaults/project_settings/nuke.json index 61001914d2..82dcf23694 100644 --- a/pype/settings/defaults/project_settings/nuke.json +++ b/pype/settings/defaults/project_settings/nuke.json @@ -87,4 +87,4 @@ ] }, "filters": {} -} +} \ No newline at end of file diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json index bd10c64457..df04e6a8aa 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/schema_project_ftrack.json @@ -211,7 +211,7 @@ }, { "type": "label", - "label": "Set Task status based on changed Asset Version status.
Version's new status on left side trigger to change task's status to first possible on right side.
- it is also tried to set version's status to task if none will match or will be available" + "label": "Change Task status based on a changed Version status.
Version's new status on the left will trigger a change of a task status to the first available from the list on right.
- if no status from the list is available it will use the same status as the version." }, { "type": "dict-modifiable",