From 019562e5ace866850d6299041e2ef88e0fda2dad Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Fri, 27 Nov 2020 21:41:49 +0100 Subject: [PATCH] integrate hierarchy ftrack temporary python 2 fix --- .../publish/integrate_hierarchy_ftrack.py | 51 +-- .../publish/integrate_hierarchy_ftrack_SP.py | 331 ++++++++++++++++++ 2 files changed, 341 insertions(+), 41 deletions(-) create mode 100644 pype/plugins/ftrack/publish/integrate_hierarchy_ftrack_SP.py diff --git a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py index ef8ee9a216..a1377cc771 100644 --- a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py +++ b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py @@ -1,13 +1,12 @@ import sys import six -import collections import pyblish.api from avalon import io -from pype.modules.ftrack.lib.avalon_sync import ( - CUST_ATTR_AUTO_SYNC, - get_pype_attr -) +try: + from pype.modules.ftrack.lib.avalon_sync import CUST_ATTR_AUTO_SYNC +except Exception: + CUST_ATTR_AUTO_SYNC = "avalon_auto_sync" class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): @@ -37,6 +36,7 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): order = pyblish.api.IntegratorOrder - 0.04 label = 'Integrate Hierarchy To Ftrack' families = ["shot"] + hosts = ["hiero"] optional = False def process(self, context): @@ -74,15 +74,6 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): self.auto_sync_on(project) def import_to_ftrack(self, input_data, parent=None): - # Prequery hiearchical custom attributes - hier_custom_attributes = get_pype_attr(self.session)[1] - hier_attr_by_key = { - attr["key"]: attr - for attr in hier_custom_attributes - } - # Get ftrack api module (as they are different per python version) - ftrack_api = self.context.data["ftrackPythonModule"] - for entity_name in input_data: entity_data = input_data[entity_name] entity_type = entity_data['entity_type'] @@ -125,34 +116,12 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): i for i in self.context if i.data['asset'] in entity['name'] ] for key in custom_attributes: - hier_attr = hier_attr_by_key.get(key) - # Use simple method if key is not hierarchical - if not hier_attr: - assert (key in entity['custom_attributes']), ( - 'Missing custom attribute key: `{0}` in attrs: ' - '`{1}`'.format(key, entity['custom_attributes'].keys()) - ) + assert (key in entity['custom_attributes']), ( + 'Missing custom attribute key: `{0}` in attrs: ' + '`{1}`'.format(key, entity['custom_attributes'].keys()) + ) - entity['custom_attributes'][key] = custom_attributes[key] - - else: - # Use ftrack operations method to set hiearchical - # attribute value. - # - this is because there may be non hiearchical custom - # attributes with different properties - entity_key = collections.OrderedDict({ - "configuration_id": hier_attr["id"], - "entity_id": entity["id"] - }) - self.session.recorded_operations.push( - ftrack_api.operation.UpdateEntityOperation( - "ContextCustomAttributeValue", - entity_key, - "value", - ftrack_api.symbol.NOT_SET, - custom_attributes[key] - ) - ) + entity['custom_attributes'][key] = custom_attributes[key] for instance in instances: instance.data['ftrackEntity'] = entity diff --git a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack_SP.py b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack_SP.py new file mode 100644 index 0000000000..ac606ed27d --- /dev/null +++ b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack_SP.py @@ -0,0 +1,331 @@ +import sys +import six +import collections +import pyblish.api +from avalon import io + +from pype.modules.ftrack.lib.avalon_sync import ( + CUST_ATTR_AUTO_SYNC, + get_pype_attr +) + + +class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): + """ + Create entities in ftrack based on collected data from premiere + Example of entry data: + { + "ProjectXS": { + "entity_type": "Project", + "custom_attributes": { + "fps": 24,... + }, + "tasks": [ + "Compositing", + "Lighting",... *task must exist as task type in project schema* + ], + "childs": { + "sq01": { + "entity_type": "Sequence", + ... + } + } + } + } + """ + + order = pyblish.api.IntegratorOrder - 0.04 + label = 'Integrate Hierarchy To Ftrack' + families = ["shot"] + hosts = ["standalonepublisher"] + optional = False + + def process(self, context): + self.context = context + if "hierarchyContext" not in self.context.data: + return + + hierarchy_context = self.context.data["hierarchyContext"] + + self.session = self.context.data["ftrackSession"] + project_name = self.context.data["projectEntity"]["name"] + query = 'Project where full_name is "{}"'.format(project_name) + project = self.session.query(query).one() + auto_sync_state = project[ + "custom_attributes"][CUST_ATTR_AUTO_SYNC] + + if not io.Session: + io.install() + + self.ft_project = None + + input_data = hierarchy_context + + # disable termporarily ftrack project's autosyncing + if auto_sync_state: + self.auto_sync_off(project) + + try: + # import ftrack hierarchy + self.import_to_ftrack(input_data) + except Exception: + raise + finally: + if auto_sync_state: + self.auto_sync_on(project) + + def import_to_ftrack(self, input_data, parent=None): + # Prequery hiearchical custom attributes + hier_custom_attributes = get_pype_attr(self.session)[1] + hier_attr_by_key = { + attr["key"]: attr + for attr in hier_custom_attributes + } + # Get ftrack api module (as they are different per python version) + ftrack_api = self.context.data["ftrackPythonModule"] + + for entity_name in input_data: + entity_data = input_data[entity_name] + entity_type = entity_data['entity_type'] + self.log.debug(entity_data) + self.log.debug(entity_type) + + if entity_type.lower() == 'project': + query = 'Project where full_name is "{}"'.format(entity_name) + entity = self.session.query(query).one() + self.ft_project = entity + self.task_types = self.get_all_task_types(entity) + + elif self.ft_project is None or parent is None: + raise AssertionError( + "Collected items are not in right order!" + ) + + # try to find if entity already exists + else: + query = ( + 'TypedContext where name is "{0}" and ' + 'project_id is "{1}"' + ).format(entity_name, self.ft_project["id"]) + try: + entity = self.session.query(query).one() + except Exception: + entity = None + + # Create entity if not exists + if entity is None: + entity = self.create_entity( + name=entity_name, + type=entity_type, + parent=parent + ) + # self.log.info('entity: {}'.format(dict(entity))) + # CUSTOM ATTRIBUTES + custom_attributes = entity_data.get('custom_attributes', []) + instances = [ + i for i in self.context if i.data['asset'] in entity['name'] + ] + for key in custom_attributes: + hier_attr = hier_attr_by_key.get(key) + # Use simple method if key is not hierarchical + if not hier_attr: + assert (key in entity['custom_attributes']), ( + 'Missing custom attribute key: `{0}` in attrs: ' + '`{1}`'.format(key, entity['custom_attributes'].keys()) + ) + + entity['custom_attributes'][key] = custom_attributes[key] + + else: + # Use ftrack operations method to set hiearchical + # attribute value. + # - this is because there may be non hiearchical custom + # attributes with different properties + entity_key = collections.OrderedDict({ + "configuration_id": hier_attr["id"], + "entity_id": entity["id"] + }) + self.session.recorded_operations.push( + ftrack_api.operation.UpdateEntityOperation( + "ContextCustomAttributeValue", + entity_key, + "value", + ftrack_api.symbol.NOT_SET, + custom_attributes[key] + ) + ) + + for instance in instances: + instance.data['ftrackEntity'] = entity + + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + self.session._configure_locations() + six.reraise(tp, value, tb) + + # TASKS + tasks = entity_data.get('tasks', []) + existing_tasks = [] + tasks_to_create = [] + for child in entity['children']: + if child.entity_type.lower() == 'task': + existing_tasks.append(child['name'].lower()) + # existing_tasks.append(child['type']['name']) + + for task_name in tasks: + task_type = tasks[task_name]["type"] + if task_name.lower() in existing_tasks: + print("Task {} already exists".format(task_name)) + continue + tasks_to_create.append((task_name, task_type)) + + for task_name, task_type in tasks_to_create: + self.create_task( + name=task_name, + task_type=task_type, + parent=entity + ) + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + self.session._configure_locations() + six.reraise(tp, value, tb) + + # Incoming links. + self.create_links(entity_data, entity) + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + self.session._configure_locations() + six.reraise(tp, value, tb) + + # Create notes. + user = self.session.query( + "User where username is \"{}\"".format(self.session.api_user) + ).first() + if user: + for comment in entity_data.get("comments", []): + entity.create_note(comment, user) + else: + self.log.warning( + "Was not able to query current User {}".format( + self.session.api_user + ) + ) + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + self.session._configure_locations() + six.reraise(tp, value, tb) + + # Import children. + if 'childs' in entity_data: + self.import_to_ftrack( + entity_data['childs'], entity) + + def create_links(self, entity_data, entity): + # Clear existing links. + for link in entity.get("incoming_links", []): + self.session.delete(link) + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + self.session._configure_locations() + six.reraise(tp, value, tb) + + # Create new links. + for input in entity_data.get("inputs", []): + input_id = io.find_one({"_id": input})["data"]["ftrackId"] + assetbuild = self.session.get("AssetBuild", input_id) + self.log.debug( + "Creating link from {0} to {1}".format( + assetbuild["name"], entity["name"] + ) + ) + self.session.create( + "TypedContextLink", {"from": assetbuild, "to": entity} + ) + + def get_all_task_types(self, project): + tasks = {} + proj_template = project['project_schema'] + temp_task_types = proj_template['_task_type_schema']['types'] + + for type in temp_task_types: + if type['name'] not in tasks: + tasks[type['name']] = type + + return tasks + + def create_task(self, name, task_type, parent): + task = self.session.create('Task', { + 'name': name, + 'parent': parent + }) + # TODO not secured!!! - check if task_type exists + self.log.info(task_type) + self.log.info(self.task_types) + task['type'] = self.task_types[task_type] + + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + self.session._configure_locations() + six.reraise(tp, value, tb) + + return task + + def create_entity(self, name, type, parent): + entity = self.session.create(type, { + 'name': name, + 'parent': parent + }) + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + self.session._configure_locations() + six.reraise(tp, value, tb) + + return entity + + def auto_sync_off(self, project): + project["custom_attributes"][CUST_ATTR_AUTO_SYNC] = False + + self.log.info("Ftrack autosync swithed off") + + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + self.session._configure_locations() + six.reraise(tp, value, tb) + + def auto_sync_on(self, project): + + project["custom_attributes"][CUST_ATTR_AUTO_SYNC] = True + + self.log.info("Ftrack autosync swithed on") + + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + self.session._configure_locations() + six.reraise(tp, value, tb)