Merge branch 'develop' into feature/prettier_jsons

This commit is contained in:
Milan Kolar 2020-12-16 20:44:28 +01:00
commit a82f7bcd1d
15 changed files with 812 additions and 140 deletions

20
pype.py
View file

@ -48,8 +48,11 @@ from igniter.tools import load_environments, add_acre_to_sys_path
from igniter import BootstrapRepos
add_acre_to_sys_path()
import acre
try:
import acre
except ImportError:
add_acre_to_sys_path()
import acre
def set_environments() -> None:
@ -101,18 +104,9 @@ def set_modules_environments():
def boot():
"""Bootstrap Pype."""
art = r"""
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ . PYPE Club .
"""
print(art)
from pype.lib.terminal_splash import play_animation
play_animation()
# find pype versions
bootstrap = BootstrapRepos()

413
pype/lib/splash.txt Normal file
View file

@ -0,0 +1,413 @@
*
.*
*
.*
*
.
*
.*
*
.
.
*
.*
.*
.*
*
.
.
*
.*
.*
.*
*
.
_.
/**
\ *
\*
*
*
.
__.
---*
\ \*
\ *
\*
*
.
\___.
/* *
\ \ *
\ \*
\ *
\*
.
|____.
/* *
\|\ *
\ \ *
\ \ *
\ \*
\/.
_/_____.
/* *
/ \ *
\ \ *
\ \ *
\ \__*
\/__.
__________.
--*-- ___*
\ \ \/_*
\ \ __*
\ \ \_*
\ \____\*
\/____/.
\____________ .
/* ___ \*
\ \ \/_\ *
\ \ _____*
\ \ \___/*
\ \____\ *
\/____/ .
|___________ .
/* ___ \ *
\|\ \/_\ \ *
\ \ _____/ *
\ \ \___/ *
\ \____\ / *
\/____/ \.
_/__________ .
/* ___ \ *
/ \ \/_\ \ *
\ \ _____/ *
\ \ \___/ ---*
\ \____\ / \__*
\/____/ \/__.
____________ .
--*-- ___ \ *
\ \ \/_\ \ *
\ \ _____/ *
\ \ \___/ ---- *
\ \____\ / \____\*
\/____/ \/____/.
____________
/\ ___ \ .
\ \ \/_\ \ *
\ \ _____/ *
\ \ \___/ ---- *
\ \____\ / \____\ .
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \ .
\ \ _____/ *
\ \ \___/ ---- *
\ \____\ / \____\ .
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ .
\ \ \___/ ---- *
\ \____\ / \____\ .
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/
\ \ \___/ ---- *
\ \____\ / \____\
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/
\ \ \___/ ---- .
\ \____\ / \____\
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ _
\ \ \___/ ----
\ \____\ / \____\
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___
\ \ \___/ ----
\ \____\ / \____\
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___
\ \ \___/ ---- \
\ \____\ / \____\
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___
\ \ \___/ ---- \
\ \____\ / \____\ \
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___
\ \ \___/ ---- \
\ \____\ / \____\ __\
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___
\ \ \___/ ---- \
\ \____\ / \____\ \__\
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___
\ \ \___/ ---- \ \
\ \____\ / \____\ \__\
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___
\ \ \___/ ---- \ \
\ \____\ / \____\ \__\
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___.
\ \ \___/ ---- \ \\
\ \____\ / \____\ \__\,
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ .
\ \ \___/ ---- \ \\
\ \____\ / \____\ \__\\,
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ _.
\ \ \___/ ---- \ \\\
\ \____\ / \____\ \__\\\
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ __.
\ \ \___/ ---- \ \\ \
\ \____\ / \____\ \__\\_/.
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___.
\ \ \___/ ---- \ \\ \\
\ \____\ / \____\ \__\\__\.
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ .
\ \ \___/ ---- \ \\ \\
\ \____\ / \____\ \__\\__\\.
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ _.
\ \ \___/ ---- \ \\ \\\
\ \____\ / \____\ \__\\__\\.
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ __.
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\_.
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ __.
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__.
\/____/ \/____/
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ .
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ *
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ O*
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ oO*
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ .oO*
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ ..oO*
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ . .oO*
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ . p.oO*
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ . Py.oO*
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ . PYp.oO*
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ . PYPe.oO*
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ . PYPE .oO*
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ . PYPE c.oO*
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ . PYPE C1.oO*
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ . PYPE ClU.oO*
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ . PYPE CluB.oO*
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ . PYPE Club .oO*
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ . PYPE Club . ..
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ . PYPE Club . ..
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ . PYPE Club . .
____________
/\ ___ \
\ \ \/_\ \
\ \ _____/ ___ ___ ___
\ \ \___/ ---- \ \\ \\ \
\ \____\ / \____\ \__\\__\\__\
\/____/ \/____/ . PYPE Club .

View file

@ -13,11 +13,10 @@
import re
import os
import sys
noColorama = False
try:
from colorama import Fore, Style, init, ansitowin32
except ImportError:
noColorama = True
import blessed
term = blessed.Terminal()
class Terminal:
@ -30,40 +29,37 @@ class Terminal:
"""
# shortcuts for colorama codes
if noColorama:
_SB = _RST = _LR = _LG = _LB = _LM = _R = _G = _B = _C = _Y = _W = ""
_LY = ""
else:
_SB = Style.BRIGHT
_RST = Style.RESET_ALL
_LR = Fore.LIGHTRED_EX
_LG = Fore.LIGHTGREEN_EX
_LB = Fore.LIGHTBLUE_EX
_LM = Fore.LIGHTMAGENTA_EX
_LY = Fore.LIGHTYELLOW_EX
_R = Fore.RED
_G = Fore.GREEN
_B = Fore.BLUE
_C = Fore.CYAN
_Y = Fore.YELLOW
_W = Fore.WHITE
_SB = term.bold
_RST = ""
_LR = term.tomato2
_LG = term.aquamarine3
_LB = term.turquoise2
_LM = term.slateblue2
_LY = term.gold
_R = term.red
_G = term.green
_B = term.blue
_C = term.cyan
_Y = term.yellow
_W = term.white
# dictionary replacing string sequences with colorized one
_sdict = {
r">>> ": _SB + _G + r">>> " + _RST,
r">>> ": _SB + _LG + r">>> " + _RST,
r"!!!(?!\sCRI|\sERR)": _SB + _R + r"!!! " + _RST,
r"\-\-\- ": _SB + _C + r"--- " + _RST,
r"\*\*\*(?!\sWRN)": _SB + _LM + r"***" + _RST,
r"\*\*\*(?!\sWRN)": _SB + _LY + r"***" + _RST,
r"\*\*\* WRN": _SB + _LY + r"*** WRN" + _RST,
r" \- ": _SB + _Y + r" - " + _RST,
r" \- ": _SB + _LY + r" - " + _RST,
r"\[ ": _SB + _LG + r"[ " + _RST,
r"\]": _SB + _LG + r"]" + _RST,
r"{": _LG + r"{",
r"}": r"}" + _RST,
r"\(": _LY + r"(",
r"\)": r")" + _RST,
r"^\.\.\. ": _SB + _LM + r"... " + _RST,
r"^\.\.\. ": _SB + _LR + r"... " + _RST,
r"!!! ERR: ":
_SB + _LR + r"!!! ERR: " + _RST,
r"!!! CRI: ":
@ -73,8 +69,7 @@ class Terminal:
}
def __init__(self):
if not noColorama:
init()
pass
@staticmethod
def _multiple_replace(text, adict):
@ -108,11 +103,6 @@ class Terminal:
str: Colorized message.
"""
if noColorama:
print(message)
return message
if not isinstance(sys.stdout, ansitowin32.StreamWrapper):
init()
colorized = Terminal.log(message)
print(colorized)

View file

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
"""Pype terminal animation."""
import blessed
from pathlib import Path
from time import sleep
term = blessed.Terminal()
def play_animation():
"""Play ASCII art Pype animation."""
print(term.home + term.clear)
frame_size = 7
splash_file = Path(__file__).parent / "splash.txt"
with splash_file.open("r") as sf:
animation = sf.readlines()
animation_length = int(len(animation) / frame_size)
current_frame = 0
for _ in range(animation_length):
frame = ""
y = 0
for scanline in animation[current_frame:current_frame + frame_size]:
frame += scanline
y += 1
with term.location(0, 0):
# term.aquamarine3_bold(frame)
print(f"{term.bold}{term.aquamarine3}{frame}{term.normal}")
sleep(0.02)
current_frame += frame_size
print(term.move_y(7))

View file

@ -1,25 +1,40 @@
from pype.modules.ftrack import BaseEvent
from pype.api import get_project_settings
class VersionToTaskStatus(BaseEvent):
"""Propagates status from version to task when changed."""
def launch(self, session, event):
'''Propagates status from version to task when changed'''
# 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
# start of event procedure ----------------------------------
for entity in event['data'].get('entities', []):
for project_id, entities_info in filtered_entities_info.items():
self.process_by_project(session, event, project_id, entities_info)
# 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_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", {})
@ -29,74 +44,162 @@ class VersionToTaskStatus(BaseEvent):
if not version_status_id:
continue
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
# 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(entity_info)
return filtered_entity_info
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
)
project_settings = self.get_settings_for_project(
session, event, project_entity=project_entity
)
project_name = project_entity["full_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
_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
if not version_status:
status_mapping = {
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:
asset_version_ids.add(entity_info["entityId"])
# Query tasks for AssetVersions
_asset_version_entities = session.query(
"AssetVersion where task_id != none and id in ({})".format(
self.join_query_keys(asset_version_ids)
)
).all()
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_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"])
# Skipt if `task_ids` are empty
if not task_ids:
return
task_entities = session.query(
"select link 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
}
# Prepare asset version by their id
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 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"])
version_status_orig = version_status["name"]
version_status_entities = session.query(
"select id, name from Status where id in ({})".format(
self.join_query_keys(status_ids)
)
).all()
# 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
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 version_status_entities
}
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)
if not status_name:
continue
status_name_low = status_name.lower()
# 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
)
)
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]
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
}
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 stat_names_low:
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
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"]
))
@ -110,16 +213,15 @@ class VersionToTaskStatus(BaseEvent):
)
)
continue
# 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()
@ -128,6 +230,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.'''

View file

@ -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):

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -71,11 +71,13 @@
"status_version_to_task": {
"enabled": true,
"mapping": {
"Complete": [
"Approved",
"Approved": [
"Complete"
]
}
},
"asset_types_to_skip": [
"scene"
]
},
"first_version_status": {
"enabled": true,

View file

@ -179,4 +179,4 @@
}
}
}
}
}

View file

@ -136,7 +136,8 @@
"enabled": false
},
"ValidateAttributes": {
"enabled": false
"enabled": false,
"attributes": {}
},
"ExtractCameraAlembic": {
"enabled": true,

View file

@ -87,4 +87,4 @@
]
},
"filters": {}
}
}

View file

@ -91,40 +91,82 @@
]
},
{
"type": "dict",
"key": "thumbnail_updates",
"label": "Update Hierarchy thumbnails",
"checkbox_key": "enabled",
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
},
{
"type": "label",
"label": "Push thumbnail from version, up through multiple hierarchy levels."
},
{
"type": "number",
"key": "levels",
"label": "Levels"
}
]
"type": "list",
"object_type": "text"
}
}]
},
{
"type": "dict",
"key": "status_version_to_task",
"label": "Sync status from Version to Task",
"checkbox_key": "enabled",
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
},
{
"type": "dict",
"key": "user_assignment",
"label": "Run script on user assignments",
"checkbox_key": "enabled",
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
}
]
"type": "label",
"label": "<b>Change Task status based on a changed Version status.</b><br/>Version's new status on the <b>left</b> will trigger a change of a task status to the first available from the list on <b>right</b>.<br/> - if no status from the list is available it will use the same status as the version."
},
{
"type": "dict-modifiable",
"key": "mapping",
"object_type":
{
"type": "list",
"object_type": "text"
}
},
{
"type": "separator"
},
{
"type": "label",
"label": "<b>Disable<b/> 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",
"key": "first_version_status",
"label": "Set status on first created version",
"checkbox_key": "enabled",
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
},
{
"type": "text",
"key": "status",
"label": "Status"
}]
},
{
"type": "dict",
"key": "next_task_update",
"label": "Update status on next task",
"checkbox_key": "enabled",
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
},
{
"type": "dict-modifiable",
"key": "mapping",
"object_type":
{
"type": "dict",
"key": "status_update",

View file

@ -1,6 +1,7 @@
aiohttp
appdirs
arrow
blessed
certifi
Click
clique==1.5.0