From ae68a414004e0cf8c08113a70a8cc0cab8c23fc1 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 16 Jan 2019 14:55:40 +0100 Subject: [PATCH 1/2] removed avalon.io so it won't change context in another apps, replaced with direct connection to DB --- .../actions/action_sync_to_avalon_local.py | 14 +- pype/ftrack/events/action_sync_to_avalon.py | 22 +-- pype/ftrack/events/event_sync_to_avalon.py | 19 +-- pype/ftrack/ftrack_utils/avalon_sync.py | 125 +++++++++++++----- pype/ftrack/ftrack_utils/ftrack_utils.py | 2 +- pype/lib.py | 10 +- 6 files changed, 109 insertions(+), 83 deletions(-) diff --git a/pype/ftrack/actions/action_sync_to_avalon_local.py b/pype/ftrack/actions/action_sync_to_avalon_local.py index 4f6f03e171..85978c0d6c 100644 --- a/pype/ftrack/actions/action_sync_to_avalon_local.py +++ b/pype/ftrack/actions/action_sync_to_avalon_local.py @@ -6,7 +6,6 @@ import json import importlib import ftrack_api -from avalon import io from ftrack_action_handler import BaseAction from pype.ftrack import ftrack_utils @@ -134,17 +133,9 @@ class SyncToAvalon(BaseAction): # ----- PROJECT ------ # store Ftrack project- self.importable[0] must be project entity!! ft_project = self.importable[0] - - # set AVALON_ env - os.environ["AVALON_PROJECT"] = ft_project["full_name"] - os.environ["AVALON_ASSET"] = ft_project["full_name"] - os.environ["AVALON_SILO"] = "" - - avalon_project = ftrack_utils.get_avalon_proj(ft_project) + avalon_project = ftrack_utils.get_avalon_project(ft_project) custom_attributes = ftrack_utils.get_avalon_attr(session) - io.install() - # Import all entities to Avalon DB for entity in self.importable: result = ftrack_utils.import_to_avalon( @@ -171,7 +162,6 @@ class SyncToAvalon(BaseAction): self.log.error( '{}: {}'.format(key, message) ) - io.uninstall() job['status'] = 'failed' session.commit() @@ -211,8 +201,6 @@ class SyncToAvalon(BaseAction): ' - Please check Log for more information' ) - io.uninstall() - if len(message) > 0: message = "Unable to sync: {}".format(message) return { diff --git a/pype/ftrack/events/action_sync_to_avalon.py b/pype/ftrack/events/action_sync_to_avalon.py index 524974b816..92a22695e1 100644 --- a/pype/ftrack/events/action_sync_to_avalon.py +++ b/pype/ftrack/events/action_sync_to_avalon.py @@ -1,16 +1,11 @@ +import os import sys import argparse import logging -import os import ftrack_api import json -import re -from pype import lib -from pype.ftrack.actions.ftrack_action_handler import BaseAction -from bson.objectid import ObjectId -from avalon import io, inventory - from pype.ftrack import ftrack_utils +from pype.ftrack.actions.ftrack_action_handler import BaseAction class Sync_To_Avalon(BaseAction): @@ -149,17 +144,9 @@ class Sync_To_Avalon(BaseAction): # ----- PROJECT ------ # store Ftrack project- self.importable[0] must be project entity!! ft_project = self.importable[0] - - # set AVALON_ env - os.environ["AVALON_PROJECT"] = ft_project["full_name"] - os.environ["AVALON_ASSET"] = ft_project["full_name"] - os.environ["AVALON_SILO"] = "" - - avalon_project = ftrack_utils.get_avalon_proj(ft_project) + avalon_project = ftrack_utils.get_avalon_project(ft_project) custom_attributes = ftrack_utils.get_avalon_attr(session) - io.install() - # Import all entities to Avalon DB for entity in self.importable: result = ftrack_utils.import_to_avalon( @@ -186,7 +173,6 @@ class Sync_To_Avalon(BaseAction): self.log.error( '{}: {}'.format(key, message) ) - io.uninstall() job['status'] = 'failed' session.commit() @@ -226,8 +212,6 @@ class Sync_To_Avalon(BaseAction): ' - Please check Log for more information' ) - io.uninstall() - if len(message) > 0: message = "Unable to sync: {}".format(message) return { diff --git a/pype/ftrack/events/event_sync_to_avalon.py b/pype/ftrack/events/event_sync_to_avalon.py index 7c1981bd5f..8ecd860644 100644 --- a/pype/ftrack/events/event_sync_to_avalon.py +++ b/pype/ftrack/events/event_sync_to_avalon.py @@ -1,8 +1,7 @@ import os import ftrack_api -from ftrack_event_handler import BaseEvent -from avalon import io from pype.ftrack import ftrack_utils +from ftrack_event_handler import BaseEvent class Sync_to_Avalon(BaseEvent): @@ -45,14 +44,12 @@ class Sync_to_Avalon(BaseEvent): self.show_message(event, message, False) return - os.environ["AVALON_PROJECT"] = ft_project['full_name'] - os.environ["AVALON_ASSET"] = ft_project["full_name"] - os.environ["AVALON_SILO"] = "" - # get avalon project if possible import_entities = [] - avalon_project = ftrack_utils.get_avalon_proj(ft_project) + custom_attributes = ftrack_utils.get_avalon_attr(session) + + avalon_project = ftrack_utils.get_avalon_project(ft_project) if avalon_project is None: import_entities.append(ft_project) @@ -79,11 +76,6 @@ class Sync_to_Avalon(BaseEvent): if len(import_entities) < 1: return - avalon_project = ftrack_utils.get_avalon_proj(ft_project) - custom_attributes = ftrack_utils.get_avalon_attr(session) - - io.install() - try: for entity in import_entities: result = ftrack_utils.import_to_avalon( @@ -109,7 +101,6 @@ class Sync_to_Avalon(BaseEvent): self.log.error( '{}: {}'.format(key, message) ) - io.uninstall() session.commit() self.show_interface(event, items) @@ -134,8 +125,6 @@ class Sync_to_Avalon(BaseEvent): self.show_interface(event, items) self.log.error(message) - io.uninstall() - return def _launch(self, event): diff --git a/pype/ftrack/ftrack_utils/avalon_sync.py b/pype/ftrack/ftrack_utils/avalon_sync.py index c7eeee6221..c268d72295 100644 --- a/pype/ftrack/ftrack_utils/avalon_sync.py +++ b/pype/ftrack/ftrack_utils/avalon_sync.py @@ -1,7 +1,7 @@ import os import re from pype import lib -from avalon import io, inventory +from avalon import io, schema from bson.objectid import ObjectId from pype.ftrack.ftrack_utils import ftrack_utils from avalon.vendor import jsonschema @@ -11,6 +11,12 @@ ValidationError = jsonschema.ValidationError log = Logger.getLogger(__name__) +def get_avalon_database(): + if io._database is None: + io.install() + return io._database + + def get_ca_mongoid(): # returns name of Custom attribute that stores mongo_id return 'avalon_mongo_id' @@ -19,6 +25,8 @@ def get_ca_mongoid(): def import_to_avalon( session, entity, ft_project, av_project, custom_attributes ): + database = get_avalon_database() + project_name = ft_project['full_name'] output = {} errors = [] @@ -46,9 +54,9 @@ def import_to_avalon( # Project //////////////////////////////////////////////////////////////// if entity_type in ['Project']: type = 'project' - name = entity['full_name'] + config = ftrack_utils.get_config(entity) - template = lib.get_avalon_project_template_schema() + schema.validate(config) av_project_code = None if av_project is not None and 'code' in av_project['data']: @@ -56,23 +64,46 @@ def import_to_avalon( ft_project_code = ft_project['name'] if av_project is None: - inventory.save(name, config, template) - av_project = io.find_one({'type': type, 'name': name}) + project_schema = lib.get_avalon_project_template_schema() + item = { + 'schema': project_schema, + 'type': type, + 'name': project_name, + 'data': dict(), + 'config': config, + 'parent': None, + } + schema.validate(item) - elif av_project['name'] != name or av_project_code != ft_project_code: + database[project_name].insert_one(item) + + av_project = database[project_name].find_one( + {'type': type} + ) + + elif ( + av_project['name'] != project_name or + ( + av_project_code is not None and + av_project_code != ft_project_code + ) + ): msg = ( 'You can\'t change {0} "{1}" to "{2}"' ', avalon wouldn\'t work properly!' '\n{0} was changed back!' ) - if av_project['name'] != name: + if av_project['name'] != project_name: entity['full_name'] = av_project['name'] errors.append( {'Changed name error': msg.format( - 'Project name', av_project['name'], name + 'Project name', av_project['name'], project_name )} ) - if av_project_code != ft_project_code: + if ( + av_project_code is not None and + av_project_code != ft_project_code + ): entity['name'] = av_project_code errors.append( {'Changed name error': msg.format( @@ -91,10 +122,10 @@ def import_to_avalon( entity, session, custom_attributes ) - io.update_many( + database[project_name].update_many( {'_id': ObjectId(projectId)}, {'$set': { - 'name': name, + 'name': project_name, 'config': config, 'data': data, }}) @@ -137,9 +168,6 @@ def import_to_avalon( name = entity['name'] - os.environ['AVALON_SILO'] = silo - os.environ['AVALON_ASSET'] = name - avalon_asset = None # existence of this custom attr is already checked if ca_mongoid not in entity['custom_attributes']: @@ -153,14 +181,27 @@ def import_to_avalon( mongo_id = entity['custom_attributes'][ca_mongoid] if mongo_id is not '': - avalon_asset = io.find_one({'_id': ObjectId(mongo_id)}) + avalon_asset = database[project_name].find_one( + {'_id': ObjectId(mongo_id)} + ) if avalon_asset is None: - avalon_asset = io.find_one({'type': 'asset', 'name': name}) + avalon_asset = database[project_name].find_one( + {'type': 'asset', 'name': name} + ) if avalon_asset is None: - mongo_id = inventory.create_asset( - name, silo, data, ObjectId(projectId) - ) + asset_schema = lib.get_avalon_asset_template_schema() + item = { + 'schema': asset_schema, + 'name': name, + 'silo': silo, + 'parent': ObjectId(projectId), + 'type': 'asset', + 'data': data + } + schema.validate(item) + mongo_id = database[project_name].insert_one(item).inserted_id + # Raise error if it seems to be different ent. with same name elif ( avalon_asset['data']['parents'] != data['parents'] or @@ -205,7 +246,9 @@ def import_to_avalon( else: asset_parent_id = avalon_asset['data']['visualParent'] - asset_parent = io.find_one({'_id': ObjectId(asset_parent_id)}) + asset_parent = database[project_name].find_one( + {'_id': ObjectId(asset_parent_id)} + ) ft_parent_id = asset_parent['data']['ftrackId'] try: entity['parent_id'] = ft_parent_id @@ -231,7 +274,7 @@ def import_to_avalon( output['errors'] = errors return output - io.update_many( + database[project_name].update_many( {'_id': ObjectId(mongo_id)}, {'$set': { 'name': name, @@ -280,8 +323,18 @@ def changeability_check_childs(entity): def get_data(entity, session, custom_attributes): + database = get_avalon_database() + entity_type = entity.entity_type + if entity_type.lower() == 'project': + ft_project = entity + elif entity_type.lower() != 'project': + ft_project = entity['project'] + av_project = get_avalon_project(ft_project) + + project_name = ft_project['full_name'] + data = {} data['ftrackId'] = entity['id'] data['entityType'] = entity_type @@ -335,10 +388,16 @@ def get_data(entity, session, custom_attributes): parentId = None for parent in parents: - parentId = io.find_one({'type': 'asset', 'name': parName})['_id'] + parentId = database[project_name]( + {'type': 'asset', 'name': parName} + )['_id'] if parent['parent'].entity_type != 'project' and parentId is None: - parent.importToAvalon(session, parent) - parentId = io.find_one({'type': 'asset', 'name': parName})['_id'] + import_to_avalon( + session, parent, ft_project, av_project, custom_attributes + ) + parentId = database[project_name].find_one( + {'type': 'asset', 'name': parName} + )['_id'] hierarchy = os.path.sep.join(folderStruct) @@ -350,27 +409,25 @@ def get_data(entity, session, custom_attributes): return data -def get_avalon_proj(ft_project): - io.install() - +def get_avalon_project(ft_project): + database = get_avalon_database() + project_name = ft_project['full_name'] ca_mongoid = get_ca_mongoid() if ca_mongoid not in ft_project['custom_attributes']: return None + # try to find by Id project_id = ft_project['custom_attributes'][ca_mongoid] try: - avalon_project = io.find_one({ - "_id": ObjectId(project_id) + avalon_project = database[project_name].find_one({ + '_id': ObjectId(project_id) }) except Exception: avalon_project = None if avalon_project is None: - avalon_project = io.find_one({ - "type": "project", - "name": ft_project["full_name"] + avalon_project = database[project_name].find_one({ + 'type': 'project' }) - io.uninstall() - return avalon_project diff --git a/pype/ftrack/ftrack_utils/ftrack_utils.py b/pype/ftrack/ftrack_utils/ftrack_utils.py index f6a239639d..4398beab8e 100644 --- a/pype/ftrack/ftrack_utils/ftrack_utils.py +++ b/pype/ftrack/ftrack_utils/ftrack_utils.py @@ -45,7 +45,7 @@ def avalon_check_name(entity, inSchema=None): if entity.entity_type in ['Project']: # data['type'] = 'project' name = entity['full_name'] - # schema = get_avalon_project_template_schema()['schema'] + # schema = get_avalon_project_template_schema() # elif entity.entity_type in ['AssetBuild','Library']: # data['silo'] = 'Assets' # else: diff --git a/pype/lib.py b/pype/lib.py index fc68e395bd..17fba41323 100644 --- a/pype/lib.py +++ b/pype/lib.py @@ -337,14 +337,17 @@ def get_asset_data(asset=None): return data + def get_avalon_project_config_schema(): schema = 'avalon-core:config-1.0' return schema + def get_avalon_project_template_schema(): - schema = {"schema": "avalon-core:inventory-1.0"} + schema = "avalon-core:inventory-1.0" return schema + def get_avalon_project_template(): from app.api import Templates @@ -364,3 +367,8 @@ def get_avalon_project_template(): proj_template['work'] = "{root}/{project}/{hierarchy}/{asset}/work/{task}" proj_template['publish'] = "{root}/{project}/{hierarchy}/{asset}/publish/{family}/{subset}/v{version}/{projectcode}_{asset}_{subset}_v{version}.{representation}" return proj_template + + +def get_avalon_asset_template_schema(): + schema = "avalon-core:asset-2.0" + return schema From 9d50a5b8b76fab433d17e2efd1ec71ab56bfc5e8 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 17 Jan 2019 16:06:34 +0100 Subject: [PATCH 2/2] more io usage replaced, added ignore_me variable to actions/events for ftrack server, added 'get avalon projects' function, fixed few bugs, added titles to show_interface in action handlers --- pype/ftrack/actions/action_Apps.py | 23 ++--- .../actions/action_sync_to_avalon_local.py | 5 +- pype/ftrack/actions/ft_utils.py | 2 + pype/ftrack/actions/ftrack_action_handler.py | 71 ++++++++------- pype/ftrack/events/action_sync_to_avalon.py | 5 +- pype/ftrack/events/event_sync_to_avalon.py | 8 +- pype/ftrack/events/ftrack_event_handler.py | 5 +- pype/ftrack/ftrack_run.py | 91 +++++++++++++------ pype/ftrack/ftrack_utils/avalon_sync.py | 15 ++- pype/lib.py | 21 +++++ 10 files changed, 153 insertions(+), 93 deletions(-) diff --git a/pype/ftrack/actions/action_Apps.py b/pype/ftrack/actions/action_Apps.py index 3f6e8b870b..fe7664470a 100644 --- a/pype/ftrack/actions/action_Apps.py +++ b/pype/ftrack/actions/action_Apps.py @@ -1,8 +1,9 @@ -import os import toml +import time from ftrack_action_handler import AppAction -from avalon import io, lib +from avalon import lib from app.api import Logger +from pype import lib as pypelib log = Logger.getLogger(__name__) @@ -28,8 +29,11 @@ def registerApp(app, session): apptoml = toml.load(abspath) + ''' REQUIRED ''' executable = apptoml['executable'] - label = apptoml.get('ftrack_label', app['label']) + + ''' OPTIONAL ''' + label = apptoml.get('ftrack_label', app.get('label', name)) icon = apptoml.get('ftrack_icon', None) description = apptoml.get('description', None) @@ -40,17 +44,7 @@ def registerApp(app, session): def register(session): - # set avalon environ - they just must exist - os.environ['AVALON_PROJECT'] = '' - os.environ['AVALON_ASSET'] = '' - os.environ['AVALON_SILO'] = '' - # Get all projects from Avalon DB - try: - io.install() - projects = sorted(io.projects(), key=lambda x: x['name']) - io.uninstall() - except Exception as e: - log.error(e) + projects = pypelib.get_all_avalon_projects() apps = [] appNames = [] @@ -65,5 +59,6 @@ def register(session): for app in apps: try: registerApp(app, session) + time.sleep(0.05) except Exception as e: log.warning("'{0}' - not proper App ({1})".format(app['name'], e)) diff --git a/pype/ftrack/actions/action_sync_to_avalon_local.py b/pype/ftrack/actions/action_sync_to_avalon_local.py index 85978c0d6c..347172acb1 100644 --- a/pype/ftrack/actions/action_sync_to_avalon_local.py +++ b/pype/ftrack/actions/action_sync_to_avalon_local.py @@ -147,7 +147,6 @@ class SyncToAvalon(BaseAction): ) if 'errors' in result and len(result['errors']) > 0: - print('error') items = [] for error in result['errors']: for key, message in error.items(): @@ -162,10 +161,12 @@ class SyncToAvalon(BaseAction): self.log.error( '{}: {}'.format(key, message) ) + title = 'Hey You! Few Errors were raised! (*look below*)' job['status'] = 'failed' session.commit() - self.show_interface(event, items) + + self.show_interface(event, items, title) return { 'success': False, 'message': "Sync to avalon FAILED" diff --git a/pype/ftrack/actions/ft_utils.py b/pype/ftrack/actions/ft_utils.py index 4b30253f9d..f6f9bfc59b 100644 --- a/pype/ftrack/actions/ft_utils.py +++ b/pype/ftrack/actions/ft_utils.py @@ -6,6 +6,8 @@ import sys import json import base64 + +ignore_me = True # sys.path.append(os.path.dirname(os.path.dirname(__file__))) # from ftrack_kredenc.lucidity.vendor import yaml # from ftrack_kredenc import lucidity diff --git a/pype/ftrack/actions/ftrack_action_handler.py b/pype/ftrack/actions/ftrack_action_handler.py index 56af11b557..b47ae24435 100644 --- a/pype/ftrack/actions/ftrack_action_handler.py +++ b/pype/ftrack/actions/ftrack_action_handler.py @@ -4,12 +4,16 @@ import os import sys import platform import ftrack_api -from avalon import io, lib +from avalon import lib import acre +from pype.ftrack import ftrack_utils from pype import api as pype +ignore_me = True + + class AppAction(object): '''Custom Action base class @@ -122,33 +126,20 @@ class AppAction(object): entity = session.get(entity_type, entity_id) # TODO Should return False if not TASK ?!!! - if entity.entity_type != 'Task': - return False - # TODO Should return False if more than one entity is selected ?!!! - if len(entities) > 1: + if ( + len(entities) > 1 or + entity.entity_type.lower() != 'task' + ): return False - ft_project = entity - if (entity.entity_type != 'Project'): - ft_project = entity['project'] + ft_project = entity['project'] - silo = "" - if 'ancestors' in entity: - for ancestor in entity['ancestors']: - silo = ancestor['name'] - break - - os.environ['AVALON_PROJECT'] = ft_project['full_name'] - os.environ['AVALON_ASSET'] = entity['name'] - os.environ['AVALON_SILO'] = silo - - io.install() - avalon_project = io.find_one({ - "type": "project", - "name": ft_project['full_name'] + database = ftrack_utils.get_avalon_database() + project_name = ft_project['full_name'] + avalon_project = database[project_name].find_one({ + "type": "project" }) - io.uninstall() if avalon_project is None: return False @@ -249,24 +240,37 @@ class AppAction(object): entity, id = entities[0] entity = session.get(entity, id) + project_name = entity['project']['full_name'] + + database = ftrack_utils.get_avalon_database() + + # Get current environments + env_list = [ + 'AVALON_PROJECT', + 'AVALON_SILO', + 'AVALON_ASSET', + 'AVALON_TASK', + 'AVALON_APP', + 'AVALON_APP_NAME' + ] + env_origin = {} + for env in env_list: + env_origin[env] = os.environ.get(env, None) # set environments for Avalon - os.environ["AVALON_PROJECT"] = entity['project']['full_name'] + os.environ["AVALON_PROJECT"] = project_name os.environ["AVALON_SILO"] = entity['ancestors'][0]['name'] os.environ["AVALON_ASSET"] = entity['parent']['name'] os.environ["AVALON_TASK"] = entity['name'] os.environ["AVALON_APP"] = self.identifier.split("_")[0] os.environ["AVALON_APP_NAME"] = self.identifier - os.environ["FTRACK_TASKID"] = id - anatomy = pype.Anatomy - io.install() - hierarchy = io.find_one({ + hierarchy = database[project_name].find_one({ "type": 'asset', "name": entity['parent']['name'] })['data']['parents'] - io.uninstall() + if hierarchy: hierarchy = os.path.join(*hierarchy) @@ -384,6 +388,10 @@ class AppAction(object): self.log.info('Starting timer for task: ' + task['name']) user.start_timer(task, force=True) + # Set origin avalon environments + for key, value in env_origin.items(): + os.environ[key] = value + return { 'success': True, 'message': "Launching {0}".format(self.label) @@ -729,7 +737,7 @@ class BaseAction(object): return result - def show_interface(self, event, items): + def show_interface(self, event, items, title=''): """ Shows interface to user who triggered event - 'items' must be list containing Ftrack interface items @@ -744,7 +752,8 @@ class BaseAction(object): topic='ftrack.action.trigger-user-interface', data=dict( type='widget', - items=items + items=items, + title=title ), target=target ), diff --git a/pype/ftrack/events/action_sync_to_avalon.py b/pype/ftrack/events/action_sync_to_avalon.py index 92a22695e1..0e55c1ed70 100644 --- a/pype/ftrack/events/action_sync_to_avalon.py +++ b/pype/ftrack/events/action_sync_to_avalon.py @@ -158,7 +158,6 @@ class Sync_To_Avalon(BaseAction): ) if 'errors' in result and len(result['errors']) > 0: - print('error') items = [] for error in result['errors']: for key, message in error.items(): @@ -173,10 +172,12 @@ class Sync_To_Avalon(BaseAction): self.log.error( '{}: {}'.format(key, message) ) + title = 'Hey You! Few Errors were raised! (*look below*)' job['status'] = 'failed' session.commit() - self.show_interface(event, items) + + self.show_interface(event, items, title) return { 'success': False, 'message': "Sync to avalon FAILED" diff --git a/pype/ftrack/events/event_sync_to_avalon.py b/pype/ftrack/events/event_sync_to_avalon.py index 8ecd860644..25b8be4359 100644 --- a/pype/ftrack/events/event_sync_to_avalon.py +++ b/pype/ftrack/events/event_sync_to_avalon.py @@ -86,7 +86,6 @@ class Sync_to_Avalon(BaseEvent): custom_attributes=custom_attributes ) if 'errors' in result and len(result['errors']) > 0: - print('error') items = [] for error in result['errors']: for key, message in error.items(): @@ -101,9 +100,9 @@ class Sync_to_Avalon(BaseEvent): self.log.error( '{}: {}'.format(key, message) ) - session.commit() - self.show_interface(event, items) + title = 'Hey You! You raised few Errors! (*look below*)' + self.show_interface(event, items, title) return if avalon_project is None: @@ -122,7 +121,8 @@ class Sync_to_Avalon(BaseEvent): 'name': 'error', 'value': ftrack_message }] - self.show_interface(event, items) + title = 'Hey You! Unknown Error has been raised! (*look below*)' + self.show_interface(event, items, title) self.log.error(message) return diff --git a/pype/ftrack/events/ftrack_event_handler.py b/pype/ftrack/events/ftrack_event_handler.py index 0cb53b74a9..7011a57ed7 100644 --- a/pype/ftrack/events/ftrack_event_handler.py +++ b/pype/ftrack/events/ftrack_event_handler.py @@ -140,7 +140,7 @@ class BaseEvent(object): on_error='ignore' ) - def show_interface(self, event, items): + def show_interface(self, event, items, title=''): """ Shows interface to user who triggered event - 'items' must be list containing Ftrack interface items @@ -153,7 +153,8 @@ class BaseEvent(object): topic='ftrack.action.trigger-user-interface', data=dict( type='widget', - items=items + items=items, + title=title ), target=target ), diff --git a/pype/ftrack/ftrack_run.py b/pype/ftrack/ftrack_run.py index db42c501a7..2a40419cb7 100644 --- a/pype/ftrack/ftrack_run.py +++ b/pype/ftrack/ftrack_run.py @@ -1,4 +1,3 @@ -import sys import os import json import threading @@ -6,6 +5,7 @@ import time import ftrack_api from app import style from app.vendor.Qt import QtCore, QtGui, QtWidgets + from pype.ftrack import credentials, login_dialog as login_dialog from pype.vendor.pynput import mouse, keyboard @@ -21,7 +21,6 @@ log = pype.Logger.getLogger(__name__, "ftrack") class FtrackRunner: - def __init__(self, main_parent=None, parent=None): self.parent = parent @@ -86,7 +85,9 @@ class FtrackRunner: # Actions part def start_action_server(self): if self.thread_action_server is None: - self.thread_action_server = threading.Thread(target=self.set_action_server) + self.thread_action_server = threading.Thread( + target=self.set_action_server + ) self.thread_action_server.daemon = True self.thread_action_server.start() @@ -95,7 +96,14 @@ class FtrackRunner: self.set_menu_visibility() def set_action_server(self): - self.action_server.run_server() + try: + self.action_server.run_server() + except Exception: + msg = 'Ftrack Action server crashed! Please try to start again.' + log.error(msg) + # TODO show message to user + self.bool_action_server = False + self.set_menu_visibility() def reset_action_server(self): self.stop_action_server() @@ -123,11 +131,19 @@ class FtrackRunner: # Actions - server self.smActionS = self.menu.addMenu("Action server") - self.aRunActionS = QtWidgets.QAction("Run action server", self.smActionS) + + self.aRunActionS = QtWidgets.QAction( + "Run action server", self.smActionS + ) + self.aResetActionS = QtWidgets.QAction( + "Reset action server", self.smActionS + ) + self.aStopActionS = QtWidgets.QAction( + "Stop action server", self.smActionS + ) + self.aRunActionS.triggered.connect(self.start_action_server) - self.aResetActionS = QtWidgets.QAction("Reset action server", self.smActionS) self.aResetActionS.triggered.connect(self.reset_action_server) - self.aStopActionS = QtWidgets.QAction("Stop action server", self.smActionS) self.aStopActionS.triggered.connect(self.stop_action_server) self.smActionS.addAction(self.aRunActionS) @@ -168,12 +184,19 @@ class FtrackRunner: self.start_timer_thread() def start_timer_thread(self): - if self.thread_timer is None: - self.thread_timer = FtrackEventsThread(self) - self.bool_timer_event = True - self.thread_timer.signal_timer_started.connect(self.timer_started) - self.thread_timer.signal_timer_stopped.connect(self.timer_stopped) - self.thread_timer.start() + try: + if self.thread_timer is None: + self.thread_timer = FtrackEventsThread(self) + self.bool_timer_event = True + self.thread_timer.signal_timer_started.connect( + self.timer_started + ) + self.thread_timer.signal_timer_stopped.connect( + self.timer_stopped + ) + self.thread_timer.start() + except Exception: + pass def stop_timer_thread(self): try: @@ -188,9 +211,15 @@ class FtrackRunner: def start_countdown_thread(self): if self.thread_timer_coundown is None: self.thread_timer_coundown = CountdownThread(self) - self.thread_timer_coundown.signal_show_question.connect(self.show_widget_timer) - self.thread_timer_coundown.signal_send_time.connect(self.change_count_widget) - self.thread_timer_coundown.signal_stop_timer.connect(self.timer_stop) + self.thread_timer_coundown.signal_show_question.connect( + self.show_widget_timer + ) + self.thread_timer_coundown.signal_send_time.connect( + self.change_count_widget + ) + self.thread_timer_coundown.signal_stop_timer.connect( + self.timer_stop + ) self.thread_timer_coundown.start() def stop_countdown_thread(self): @@ -255,7 +284,9 @@ class FtrackEventsThread(QtCore.QThread): def run(self): self.timer_session = ftrack_api.Session(auto_connect_event_hub=True) self.timer_session.event_hub.subscribe( - 'topic=ftrack.update and source.user.username={}'.format(self.username), + 'topic=ftrack.update and source.user.username={}'.format( + self.username + ), self.event_handler) user_query = 'User where username is "{}"'.format(self.username) @@ -273,7 +304,7 @@ class FtrackEventsThread(QtCore.QThread): try: if event['data']['entities'][0]['objectTypeId'] != 'timer': return - except: + except Exception: return new = event['data']['entities'][0]['changes']['start']['new'] @@ -301,12 +332,6 @@ class FtrackEventsThread(QtCore.QThread): def ftrack_restart_timer(self): try: - last_task = None - if "FTRACK_LAST_TASK_ID" in os.environ: - task_id = os.environ["FTRACK_LAST_TASK_ID"] - query = 'Task where id is {}'.format(task_id) - last_task = self.timer_session.query(query).one() - if (self.last_task is not None) and (self.user is not None): self.user.start_timer(self.last_task) self.timer_session.commit() @@ -386,7 +411,11 @@ class CountdownThread(QtCore.QThread): json_dict = json.load(data_file) data = json_dict['timer'] except Exception as e: - msg = 'Loading "Ftrack Config file" Failed. Please check log for more information. Times are set to default.' + msg = ( + 'Loading "Ftrack Config file" Failed.' + ' Please check log for more information.' + ' Times are set to default.' + ) log.warning("{} - {}".format(msg, str(e))) data = self.validate_timer_values(data) @@ -485,15 +514,17 @@ class StopTimer(QtWidgets.QWidget): def _main(self): self.main = QtWidgets.QVBoxLayout() - self.main.setObjectName("main") + self.main.setObjectName('main') self.form = QtWidgets.QFormLayout() self.form.setContentsMargins(10, 15, 10, 5) - self.form.setObjectName("form") + self.form.setObjectName('form') - msg_info = "You didn't work for a long time." - msg_question = "Would you like to stop Ftrack timer?" - msg_stopped = "Your Ftrack timer was stopped. Do you want to start again?" + msg_info = 'You didn\'t work for a long time.' + msg_question = 'Would you like to stop Ftrack timer?' + msg_stopped = ( + 'Your Ftrack timer was stopped. Do you want to start again?' + ) self.lbl_info = QtWidgets.QLabel(msg_info) self.lbl_info.setFont(self.font) diff --git a/pype/ftrack/ftrack_utils/avalon_sync.py b/pype/ftrack/ftrack_utils/avalon_sync.py index c268d72295..648c119b2f 100644 --- a/pype/ftrack/ftrack_utils/avalon_sync.py +++ b/pype/ftrack/ftrack_utils/avalon_sync.py @@ -1,7 +1,8 @@ import os import re from pype import lib -from avalon import io, schema +from pype.lib import get_avalon_database +from avalon import schema from bson.objectid import ObjectId from pype.ftrack.ftrack_utils import ftrack_utils from avalon.vendor import jsonschema @@ -11,12 +12,6 @@ ValidationError = jsonschema.ValidationError log = Logger.getLogger(__name__) -def get_avalon_database(): - if io._database is None: - io.install() - return io._database - - def get_ca_mongoid(): # returns name of Custom attribute that stores mongo_id return 'avalon_mongo_id' @@ -213,6 +208,10 @@ def import_to_avalon( errors.append({'Entity name duplication': msg}) output['errors'] = errors return output + + # Store new ID (in case that asset was removed from DB) + else: + mongo_id = avalon_asset['_id'] else: if avalon_asset['name'] != entity['name']: if silo is None or changeability_check_childs(entity) is False: @@ -388,7 +387,7 @@ def get_data(entity, session, custom_attributes): parentId = None for parent in parents: - parentId = database[project_name]( + parentId = database[project_name].find_one( {'type': 'asset', 'name': parName} )['_id'] if parent['parent'].entity_type != 'project' and parentId is None: diff --git a/pype/lib.py b/pype/lib.py index 17fba41323..781e665224 100644 --- a/pype/lib.py +++ b/pype/lib.py @@ -372,3 +372,24 @@ def get_avalon_project_template(): def get_avalon_asset_template_schema(): schema = "avalon-core:asset-2.0" return schema + + +def get_avalon_database(): + if io._database is None: + project = os.environ.get('AVALON_PROJECT', '') + asset = os.environ.get('AVALON_ASSET', '') + silo = os.environ.get('AVALON_SILO', '') + os.environ['AVALON_PROJECT'] = project + os.environ['AVALON_ASSET'] = asset + os.environ['AVALON_SILO'] = silo + io.install() + return io._database + + +def get_all_avalon_projects(): + db = get_avalon_database() + project_names = db.collection_names() + projects = [] + for name in project_names: + projects.append(db[name].find_one({'type': 'project'})) + return projects