mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 16:34:53 +01:00
Merge branch 'develop' into backup/app_group_in_name
# Conflicts: # openpype/lib/applications.py # pype/hosts/premiere/extensions/com.pype/jsx/pype.jsx
This commit is contained in:
commit
9a6792ffab
1717 changed files with 4525 additions and 57466 deletions
23
openpype/settings/__init__.py
Normal file
23
openpype/settings/__init__.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
from .lib import (
|
||||
get_system_settings,
|
||||
get_project_settings,
|
||||
get_current_project_settings,
|
||||
get_anatomy_settings,
|
||||
get_environments
|
||||
)
|
||||
from .entities import (
|
||||
SystemSettings,
|
||||
ProjectSettings
|
||||
)
|
||||
|
||||
|
||||
__all__ = (
|
||||
"get_system_settings",
|
||||
"get_project_settings",
|
||||
"get_current_project_settings",
|
||||
"get_anatomy_settings",
|
||||
"get_environments",
|
||||
|
||||
"SystemSettings",
|
||||
"ProjectSettings"
|
||||
)
|
||||
46
openpype/settings/constants.py
Normal file
46
openpype/settings/constants.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import re
|
||||
|
||||
|
||||
# Metadata keys for work with studio and project overrides
|
||||
M_OVERRIDEN_KEY = "__overriden_keys__"
|
||||
# Metadata key for storing information about environments
|
||||
M_ENVIRONMENT_KEY = "__environment_keys__"
|
||||
# Metadata key for storing dynamic created labels
|
||||
M_DYNAMIC_KEY_LABEL = "__dynamic_keys_labels__"
|
||||
|
||||
METADATA_KEYS = (
|
||||
M_OVERRIDEN_KEY,
|
||||
M_ENVIRONMENT_KEY,
|
||||
M_DYNAMIC_KEY_LABEL
|
||||
)
|
||||
|
||||
# File where studio's system overrides are stored
|
||||
GLOBAL_SETTINGS_KEY = "global_settings"
|
||||
SYSTEM_SETTINGS_KEY = "system_settings"
|
||||
PROJECT_SETTINGS_KEY = "project_settings"
|
||||
PROJECT_ANATOMY_KEY = "project_anatomy"
|
||||
LOCAL_SETTING_KEY = "local_settings"
|
||||
|
||||
DEFAULT_PROJECT_KEY = "__default_project__"
|
||||
|
||||
KEY_ALLOWED_SYMBOLS = "a-zA-Z0-9-_ "
|
||||
KEY_REGEX = re.compile(r"^[{}]+$".format(KEY_ALLOWED_SYMBOLS))
|
||||
|
||||
|
||||
__all__ = (
|
||||
"M_OVERRIDEN_KEY",
|
||||
"M_ENVIRONMENT_KEY",
|
||||
"M_DYNAMIC_KEY_LABEL",
|
||||
|
||||
"METADATA_KEYS",
|
||||
|
||||
"SYSTEM_SETTINGS_KEY",
|
||||
"PROJECT_SETTINGS_KEY",
|
||||
"PROJECT_ANATOMY_KEY",
|
||||
"LOCAL_SETTING_KEY",
|
||||
|
||||
"DEFAULT_PROJECT_KEY",
|
||||
|
||||
"KEY_ALLOWED_SYMBOLS",
|
||||
"KEY_REGEX"
|
||||
)
|
||||
26
openpype/settings/defaults/project_anatomy/attributes.json
Normal file
26
openpype/settings/defaults/project_anatomy/attributes.json
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"fps": 25.0,
|
||||
"frameStart": 1001,
|
||||
"frameEnd": 1001,
|
||||
"clipIn": 1,
|
||||
"clipOut": 1,
|
||||
"handleStart": 0,
|
||||
"handleEnd": 0,
|
||||
"resolutionWidth": 1920,
|
||||
"resolutionHeight": 1080,
|
||||
"pixelAspect": 1.0,
|
||||
"applications": [
|
||||
"maya_2020",
|
||||
"nuke_12-2",
|
||||
"nukex_12-2",
|
||||
"hiero_12-2",
|
||||
"resolve_16",
|
||||
"houdini_18-5",
|
||||
"blender_2-90",
|
||||
"harmony_20",
|
||||
"photoshop_2021",
|
||||
"aftereffects_2021",
|
||||
"unreal_4-24"
|
||||
],
|
||||
"tools_env": []
|
||||
}
|
||||
129
openpype/settings/defaults/project_anatomy/imageio.json
Normal file
129
openpype/settings/defaults/project_anatomy/imageio.json
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
{
|
||||
"hiero": {
|
||||
"workfile": {
|
||||
"ocioConfigName": "nuke-default",
|
||||
"ocioconfigpath": {
|
||||
"windows": [],
|
||||
"darwin": [],
|
||||
"linux": []
|
||||
},
|
||||
"workingSpace": "linear",
|
||||
"sixteenBitLut": "sRGB",
|
||||
"eightBitLut": "sRGB",
|
||||
"floatLut": "linear",
|
||||
"logLut": "Cineon",
|
||||
"viewerLut": "sRGB",
|
||||
"thumbnailLut": "sRGB"
|
||||
},
|
||||
"regexInputs": {
|
||||
"inputs": [
|
||||
{
|
||||
"regex": "[^-a-zA-Z0-9](plateRef).*(?=mp4)",
|
||||
"colorspace": "sRGB"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"nuke": {
|
||||
"workfile": {
|
||||
"colorManagement": "Nuke",
|
||||
"OCIO_config": "nuke-default",
|
||||
"customOCIOConfigPath": {
|
||||
"windows": [],
|
||||
"darwin": [],
|
||||
"linux": []
|
||||
},
|
||||
"workingSpaceLUT": "linear",
|
||||
"monitorLut": "sRGB",
|
||||
"int8Lut": "sRGB",
|
||||
"int16Lut": "sRGB",
|
||||
"logLut": "Cineon",
|
||||
"floatLut": "linear"
|
||||
},
|
||||
"nodes": {
|
||||
"requiredNodes": [
|
||||
{
|
||||
"plugins": [
|
||||
"CreateWriteRender"
|
||||
],
|
||||
"nukeNodeClass": "Write",
|
||||
"knobs": [
|
||||
{
|
||||
"name": "file_type",
|
||||
"value": "exr"
|
||||
},
|
||||
{
|
||||
"name": "datatype",
|
||||
"value": "16 bit half"
|
||||
},
|
||||
{
|
||||
"name": "compression",
|
||||
"value": "Zip (1 scanline)"
|
||||
},
|
||||
{
|
||||
"name": "autocrop",
|
||||
"value": "True"
|
||||
},
|
||||
{
|
||||
"name": "tile_color",
|
||||
"value": "0xff0000ff"
|
||||
},
|
||||
{
|
||||
"name": "channels",
|
||||
"value": "rgb"
|
||||
},
|
||||
{
|
||||
"name": "colorspace",
|
||||
"value": "linear"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"plugins": [
|
||||
"CreateWritePrerender"
|
||||
],
|
||||
"nukeNodeClass": "Write",
|
||||
"knobs": [
|
||||
{
|
||||
"name": "file_type",
|
||||
"value": "exr"
|
||||
},
|
||||
{
|
||||
"name": "datatype",
|
||||
"value": "16 bit half"
|
||||
},
|
||||
{
|
||||
"name": "compression",
|
||||
"value": "Zip (1 scanline)"
|
||||
},
|
||||
{
|
||||
"name": "autocrop",
|
||||
"value": "False"
|
||||
},
|
||||
{
|
||||
"name": "tile_color",
|
||||
"value": "0xff0000ff"
|
||||
},
|
||||
{
|
||||
"name": "channels",
|
||||
"value": "rgb"
|
||||
},
|
||||
{
|
||||
"name": "colorspace",
|
||||
"value": "linear"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"customNodes": []
|
||||
},
|
||||
"regexInputs": {
|
||||
"inputs": [
|
||||
{
|
||||
"regex": "[^-a-zA-Z0-9]beauty[^-a-zA-Z0-9]",
|
||||
"colorspace": "linear"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
7
openpype/settings/defaults/project_anatomy/roots.json
Normal file
7
openpype/settings/defaults/project_anatomy/roots.json
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"work": {
|
||||
"windows": "C:/projects",
|
||||
"darwin": "/Volumes/path",
|
||||
"linux": "/mnt/share/projects"
|
||||
}
|
||||
}
|
||||
44
openpype/settings/defaults/project_anatomy/tasks.json
Normal file
44
openpype/settings/defaults/project_anatomy/tasks.json
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"Generic": {
|
||||
"short_name": "gener"
|
||||
},
|
||||
"Art": {
|
||||
"short_name": "art"
|
||||
},
|
||||
"Modeling": {
|
||||
"short_name": "mdl"
|
||||
},
|
||||
"Texture": {
|
||||
"short_name": "tex"
|
||||
},
|
||||
"Lookdev": {
|
||||
"short_name": "look"
|
||||
},
|
||||
"Rigging": {
|
||||
"short_name": "rig"
|
||||
},
|
||||
"Edit": {
|
||||
"short_name": "edit"
|
||||
},
|
||||
"Layout": {
|
||||
"short_name": "lay"
|
||||
},
|
||||
"Setdress": {
|
||||
"short_name": "dress"
|
||||
},
|
||||
"Animation": {
|
||||
"short_name": "anim"
|
||||
},
|
||||
"FX": {
|
||||
"short_name": "fx"
|
||||
},
|
||||
"Lighting": {
|
||||
"short_name": "lgt"
|
||||
},
|
||||
"Paint": {
|
||||
"short_name": "paint"
|
||||
},
|
||||
"Compositing": {
|
||||
"short_name": "comp"
|
||||
}
|
||||
}
|
||||
31
openpype/settings/defaults/project_anatomy/templates.json
Normal file
31
openpype/settings/defaults/project_anatomy/templates.json
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"defaults": {
|
||||
"version_padding": 3,
|
||||
"version": "v{version:0>{@version_padding}}",
|
||||
"frame_padding": 4,
|
||||
"frame": "{frame:0>{@frame_padding}}"
|
||||
},
|
||||
"work": {
|
||||
"folder": "{root[work]}/{project[name]}/{hierarchy}/{asset}/work/{task}",
|
||||
"file": "{project[code]}_{asset}_{task}_{@version}<_{comment}>.{ext}",
|
||||
"path": "{@folder}/{@file}"
|
||||
},
|
||||
"render": {
|
||||
"folder": "{root[work]}/{project[name]}/{hierarchy}/{asset}/publish/render/{subset}/{@version}",
|
||||
"file": "{project[code]}_{asset}_{subset}_{@version}<_{output}><.{@frame}>.{ext}",
|
||||
"path": "{@folder}/{@file}"
|
||||
},
|
||||
"publish": {
|
||||
"folder": "{root[work]}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}/{@version}",
|
||||
"file": "{project[code]}_{asset}_{subset}_{@version}<_{output}><.{@frame}>.{ext}",
|
||||
"path": "{@folder}/{@file}",
|
||||
"thumbnail": "{thumbnail_root}/{project[name]}/{_id}_{thumbnail_type}.{ext}"
|
||||
},
|
||||
"hero": {
|
||||
"folder": "{root[work]}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}/hero",
|
||||
"file": "{project[code]}_{asset}_{subset}_hero<_{output}><.{frame}>.{ext}",
|
||||
"path": "{@folder}/{@file}"
|
||||
},
|
||||
"delivery": {},
|
||||
"others": {}
|
||||
}
|
||||
13
openpype/settings/defaults/project_settings/celaction.json
Normal file
13
openpype/settings/defaults/project_settings/celaction.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"publish": {
|
||||
"ExtractCelactionDeadline": {
|
||||
"enabled": true,
|
||||
"deadline_department": "",
|
||||
"deadline_priority": 50,
|
||||
"deadline_pool": "",
|
||||
"deadline_pool_secondary": "",
|
||||
"deadline_group": "",
|
||||
"deadline_chunk_size": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
51
openpype/settings/defaults/project_settings/deadline.json
Normal file
51
openpype/settings/defaults/project_settings/deadline.json
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
"publish": {
|
||||
"MayaSubmitDeadline": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true,
|
||||
"tile_assembler_plugin": "oiio",
|
||||
"use_published": true,
|
||||
"asset_dependencies": true,
|
||||
"group": "none",
|
||||
"limit": []
|
||||
},
|
||||
"NukeSubmitDeadline": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true,
|
||||
"use_published": true,
|
||||
"priority": 50,
|
||||
"chunk_size": 10,
|
||||
"primary_pool": "",
|
||||
"secondary_pool": "",
|
||||
"group": "",
|
||||
"department": "",
|
||||
"limit_groups": {}
|
||||
},
|
||||
"HarmonySubmitDeadline": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true,
|
||||
"use_published": true,
|
||||
"priority": 50,
|
||||
"chunk_size": 10000,
|
||||
"primary_pool": "",
|
||||
"secondary_pool": "",
|
||||
"group": "",
|
||||
"department": ""
|
||||
},
|
||||
"AfterEffectsSubmitDeadline": {
|
||||
"enabled": true,
|
||||
"optional": false,
|
||||
"active": true,
|
||||
"use_published": true,
|
||||
"priority": 50,
|
||||
"chunk_size": 10000,
|
||||
"primary_pool": "",
|
||||
"secondary_pool": "",
|
||||
"group": "",
|
||||
"department": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
206
openpype/settings/defaults/project_settings/ftrack.json
Normal file
206
openpype/settings/defaults/project_settings/ftrack.json
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
{
|
||||
"events": {
|
||||
"sync_to_avalon": {
|
||||
"enabled": true,
|
||||
"statuses_name_change": [
|
||||
"ready",
|
||||
"not ready"
|
||||
]
|
||||
},
|
||||
"sync_hier_entity_attributes": {
|
||||
"enabled": true,
|
||||
"interest_entity_types": [
|
||||
"Shot",
|
||||
"Asset Build"
|
||||
],
|
||||
"interest_attributes": [
|
||||
"frameStart",
|
||||
"frameEnd"
|
||||
],
|
||||
"action_enabled": true,
|
||||
"role_list": [
|
||||
"Pypeclub",
|
||||
"Administrator",
|
||||
"Project Manager"
|
||||
]
|
||||
},
|
||||
"clone_review_session": {
|
||||
"enabled": true,
|
||||
"role_list": [
|
||||
"Pypeclub",
|
||||
"Administrator",
|
||||
"Project Manager"
|
||||
]
|
||||
},
|
||||
"thumbnail_updates": {
|
||||
"enabled": true,
|
||||
"levels": 1
|
||||
},
|
||||
"user_assignment": {
|
||||
"enabled": true
|
||||
},
|
||||
"status_update": {
|
||||
"enabled": true,
|
||||
"mapping": {
|
||||
"In Progress": [
|
||||
"__any__"
|
||||
],
|
||||
"Ready": [
|
||||
"Not Ready"
|
||||
],
|
||||
"__ignore__": [
|
||||
"in prgoress",
|
||||
"omitted",
|
||||
"on hold"
|
||||
]
|
||||
}
|
||||
},
|
||||
"status_task_to_parent": {
|
||||
"enabled": true,
|
||||
"parent_object_types": [
|
||||
"Shot",
|
||||
"Asset Build"
|
||||
],
|
||||
"parent_status_match_all_task_statuses": {
|
||||
"Completed": [
|
||||
"Approved",
|
||||
"Omitted"
|
||||
]
|
||||
},
|
||||
"parent_status_by_task_status": [
|
||||
{
|
||||
"new_status": "In Progress",
|
||||
"task_statuses": [
|
||||
"in progress",
|
||||
"change requested",
|
||||
"retake",
|
||||
"pending review"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"status_task_to_version": {
|
||||
"enabled": true,
|
||||
"mapping": {},
|
||||
"asset_types_filter": []
|
||||
},
|
||||
"status_version_to_task": {
|
||||
"enabled": true,
|
||||
"mapping": {},
|
||||
"asset_types_to_skip": []
|
||||
},
|
||||
"first_version_status": {
|
||||
"enabled": true,
|
||||
"status": ""
|
||||
},
|
||||
"next_task_update": {
|
||||
"enabled": true,
|
||||
"mapping": {
|
||||
"Not Ready": "Ready"
|
||||
},
|
||||
"ignored_statuses": [
|
||||
"Omitted"
|
||||
],
|
||||
"name_sorting": false
|
||||
}
|
||||
},
|
||||
"user_handlers": {
|
||||
"application_launch_statuses": {
|
||||
"enabled": true,
|
||||
"ignored_statuses": [
|
||||
"In Progress",
|
||||
"Omitted",
|
||||
"On hold",
|
||||
"Approved"
|
||||
],
|
||||
"status_change": {
|
||||
"In Progress": []
|
||||
}
|
||||
},
|
||||
"create_update_attributes": {
|
||||
"role_list": [
|
||||
"Pypeclub",
|
||||
"Administrator"
|
||||
]
|
||||
},
|
||||
"prepare_project": {
|
||||
"enabled": true,
|
||||
"role_list": [
|
||||
"Pypeclub",
|
||||
"Administrator",
|
||||
"Project manager"
|
||||
]
|
||||
},
|
||||
"clean_hierarchical_attr": {
|
||||
"enabled": true,
|
||||
"role_list": [
|
||||
"Pypeclub",
|
||||
"Administrator",
|
||||
"Project manager"
|
||||
]
|
||||
},
|
||||
"delete_asset_subset": {
|
||||
"enabled": true,
|
||||
"role_list": [
|
||||
"Pypeclub",
|
||||
"Administrator",
|
||||
"Project Manager"
|
||||
]
|
||||
},
|
||||
"delete_old_versions": {
|
||||
"enabled": true,
|
||||
"role_list": [
|
||||
"Pypeclub",
|
||||
"Project Manager",
|
||||
"Administrator"
|
||||
]
|
||||
},
|
||||
"delivery_action": {
|
||||
"enabled": true,
|
||||
"role_list": [
|
||||
"Pypeclub",
|
||||
"Project Manager",
|
||||
"Administrator"
|
||||
]
|
||||
},
|
||||
"store_thubmnail_to_avalon": {
|
||||
"enabled": true,
|
||||
"role_list": [
|
||||
"Pypeclub",
|
||||
"Project Manager",
|
||||
"Administrator"
|
||||
]
|
||||
},
|
||||
"job_killer": {
|
||||
"enabled": true,
|
||||
"role_list": [
|
||||
"Pypeclub",
|
||||
"Administrator"
|
||||
]
|
||||
},
|
||||
"sync_to_avalon_local": {
|
||||
"enabled": true,
|
||||
"role_list": [
|
||||
"Pypeclub",
|
||||
"Administrator"
|
||||
]
|
||||
},
|
||||
"seed_project": {
|
||||
"enabled": true,
|
||||
"role_list": [
|
||||
"Pypeclub"
|
||||
]
|
||||
}
|
||||
},
|
||||
"publish": {
|
||||
"IntegrateFtrackNote": {
|
||||
"enabled": true,
|
||||
"note_with_intent_template": "",
|
||||
"note_labels": []
|
||||
},
|
||||
"ValidateFtrackAttributes": {
|
||||
"enabled": false,
|
||||
"ftrack_custom_attributes": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
224
openpype/settings/defaults/project_settings/global.json
Normal file
224
openpype/settings/defaults/project_settings/global.json
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
{
|
||||
"publish": {
|
||||
"IntegrateHeroVersion": {
|
||||
"enabled": true
|
||||
},
|
||||
"ExtractJpegEXR": {
|
||||
"enabled": true,
|
||||
"ffmpeg_args": {
|
||||
"input": [],
|
||||
"output": []
|
||||
}
|
||||
},
|
||||
"ExtractReview": {
|
||||
"enabled": true,
|
||||
"profiles": [
|
||||
{
|
||||
"families": [],
|
||||
"hosts": [],
|
||||
"outputs": {
|
||||
"h264": {
|
||||
"ext": "mp4",
|
||||
"tags": [
|
||||
"burnin",
|
||||
"ftrackreview"
|
||||
],
|
||||
"ffmpeg_args": {
|
||||
"video_filters": [],
|
||||
"audio_filters": [],
|
||||
"input": [
|
||||
"-gamma 2.2"
|
||||
],
|
||||
"output": [
|
||||
"-pix_fmt yuv420p",
|
||||
"-crf 18",
|
||||
"-intra"
|
||||
]
|
||||
},
|
||||
"filter": {
|
||||
"families": [
|
||||
"render",
|
||||
"review",
|
||||
"ftrack"
|
||||
]
|
||||
},
|
||||
"width": 0,
|
||||
"height": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"ExtractBurnin": {
|
||||
"enabled": true,
|
||||
"options": {
|
||||
"font_size": 42,
|
||||
"opacity": 1.0,
|
||||
"bg_opacity": 0.5,
|
||||
"x_offset": 5,
|
||||
"y_offset": 5,
|
||||
"bg_padding": 5
|
||||
},
|
||||
"profiles": [
|
||||
{
|
||||
"families": [],
|
||||
"hosts": [],
|
||||
"burnins": {
|
||||
"burnin": {
|
||||
"TOP_LEFT": "{yy}-{mm}-{dd}",
|
||||
"TOP_CENTERED": "",
|
||||
"TOP_RIGHT": "{anatomy[version]}",
|
||||
"BOTTOM_LEFT": "{username}",
|
||||
"BOTTOM_CENTERED": "{asset}",
|
||||
"BOTTOM_RIGHT": "{frame_start}-{current_frame}-{frame_end}"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"IntegrateAssetNew": {
|
||||
"template_name_profiles": {
|
||||
"publish": {
|
||||
"families": [],
|
||||
"tasks": []
|
||||
},
|
||||
"render": {
|
||||
"families": [
|
||||
"review",
|
||||
"render",
|
||||
"prerender"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ProcessSubmittedJobOnFarm": {
|
||||
"enabled": true,
|
||||
"deadline_department": "",
|
||||
"deadline_pool": "",
|
||||
"deadline_group": "",
|
||||
"deadline_chunk_size": 1,
|
||||
"deadline_priority": 50,
|
||||
"aov_filter": {
|
||||
"maya": [
|
||||
".+(?:\\.|_)([Bb]eauty)(?:\\.|_).*"
|
||||
],
|
||||
"nuke": [],
|
||||
"aftereffects": [
|
||||
".*"
|
||||
],
|
||||
"celaction": [
|
||||
".*"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"tools": {
|
||||
"creator": {
|
||||
"families_smart_select": {
|
||||
"Render": [
|
||||
"light",
|
||||
"render"
|
||||
],
|
||||
"Model": [
|
||||
"model"
|
||||
],
|
||||
"Layout": [
|
||||
"layout"
|
||||
],
|
||||
"Look": [
|
||||
"look"
|
||||
],
|
||||
"Rig": [
|
||||
"rigging",
|
||||
"rig"
|
||||
]
|
||||
},
|
||||
"subset_name_profiles": [
|
||||
{
|
||||
"families": [],
|
||||
"hosts": [],
|
||||
"tasks": [],
|
||||
"template": "{family}{Variant}"
|
||||
},
|
||||
{
|
||||
"families": [
|
||||
"render"
|
||||
],
|
||||
"hosts": [],
|
||||
"tasks": [],
|
||||
"template": "{family}{Task}{Variant}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Workfiles": {
|
||||
"last_workfile_on_startup": [
|
||||
{
|
||||
"hosts": [],
|
||||
"tasks": [],
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"sw_folders": {
|
||||
"compositing": [
|
||||
"nuke",
|
||||
"ae"
|
||||
],
|
||||
"modeling": [
|
||||
"maya",
|
||||
"blender",
|
||||
"zbrush"
|
||||
],
|
||||
"lookdev": [
|
||||
"substance",
|
||||
"textures"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"project_folder_structure": {
|
||||
"__project_root__": {
|
||||
"prod": {},
|
||||
"resources": {
|
||||
"footage": {
|
||||
"plates": {},
|
||||
"offline": {}
|
||||
},
|
||||
"audio": {},
|
||||
"art_dept": {}
|
||||
},
|
||||
"editorial": {},
|
||||
"assets[ftrack.Library]": {
|
||||
"characters[ftrack]": {},
|
||||
"locations[ftrack]": {}
|
||||
},
|
||||
"shots[ftrack.Sequence]": {
|
||||
"scripts": {},
|
||||
"editorial[ftrack.Folder]": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sync_server": {
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"retry_cnt": "3",
|
||||
"loop_delay": "60",
|
||||
"active_site": "studio",
|
||||
"remote_site": "studio"
|
||||
},
|
||||
"sites": {
|
||||
"gdrive": {
|
||||
"provider": "gdrive",
|
||||
"credentials_url": "",
|
||||
"root": {
|
||||
"work": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"project_plugins": {
|
||||
"windows": [],
|
||||
"darwin": [],
|
||||
"linux": []
|
||||
},
|
||||
"project_environments": {}
|
||||
}
|
||||
20
openpype/settings/defaults/project_settings/harmony.json
Normal file
20
openpype/settings/defaults/project_settings/harmony.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"general": {
|
||||
"skip_resolution_check": [],
|
||||
"skip_timelines_check": []
|
||||
},
|
||||
"publish": {
|
||||
"CollectPalettes": {
|
||||
"allowed_tasks": [
|
||||
"."
|
||||
]
|
||||
},
|
||||
"HarmonySubmitDeadline": {
|
||||
"use_published": false,
|
||||
"priority": 50,
|
||||
"primary_pool": "",
|
||||
"secondary_pool": "",
|
||||
"chunk_size": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
32
openpype/settings/defaults/project_settings/hiero.json
Normal file
32
openpype/settings/defaults/project_settings/hiero.json
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"create": {
|
||||
"CreateShotClip": {
|
||||
"hierarchy": "{folder}/{sequence}",
|
||||
"clipRename": true,
|
||||
"clipName": "{track}{sequence}{shot}",
|
||||
"countFrom": 10,
|
||||
"countSteps": 10,
|
||||
"folder": "shots",
|
||||
"episode": "ep01",
|
||||
"sequence": "sq01",
|
||||
"track": "{_track_}",
|
||||
"shot": "sh###",
|
||||
"vSyncOn": false,
|
||||
"workfileFrameStart": 1001,
|
||||
"handleStart": 10,
|
||||
"handleEnd": 10
|
||||
}
|
||||
},
|
||||
"publish": {
|
||||
"CollectInstanceVersion": {
|
||||
"enabled": false
|
||||
},
|
||||
"ExtractReviewCutUpVideo": {
|
||||
"enabled": true,
|
||||
"tags_addition": [
|
||||
"review"
|
||||
]
|
||||
}
|
||||
},
|
||||
"filters": {}
|
||||
}
|
||||
562
openpype/settings/defaults/project_settings/maya.json
Normal file
562
openpype/settings/defaults/project_settings/maya.json
Normal file
|
|
@ -0,0 +1,562 @@
|
|||
{
|
||||
"ext_mapping": {
|
||||
"model": "ma",
|
||||
"mayaAscii": "ma",
|
||||
"camera": "ma",
|
||||
"rig": "ma",
|
||||
"workfile": "ma",
|
||||
"yetiRig": "ma"
|
||||
},
|
||||
"create": {
|
||||
"CreateAnimation": {
|
||||
"enabled": true,
|
||||
"defaults": [
|
||||
"Main"
|
||||
]
|
||||
},
|
||||
"CreateAss": {
|
||||
"enabled": true,
|
||||
"defaults": [
|
||||
"Main"
|
||||
]
|
||||
},
|
||||
"CreateAssembly": {
|
||||
"enabled": true,
|
||||
"defaults": [
|
||||
"Main"
|
||||
]
|
||||
},
|
||||
"CreateCamera": {
|
||||
"enabled": true,
|
||||
"defaults": [
|
||||
"Main"
|
||||
]
|
||||
},
|
||||
"CreateLayout": {
|
||||
"enabled": true,
|
||||
"defaults": [
|
||||
"Main"
|
||||
]
|
||||
},
|
||||
"CreateLook": {
|
||||
"enabled": true,
|
||||
"defaults": [
|
||||
"Main"
|
||||
]
|
||||
},
|
||||
"CreateMayaScene": {
|
||||
"enabled": true,
|
||||
"defaults": [
|
||||
"Main"
|
||||
]
|
||||
},
|
||||
"CreateModel": {
|
||||
"enabled": true,
|
||||
"defaults": [
|
||||
"Main",
|
||||
"Proxy",
|
||||
"Sculpt"
|
||||
]
|
||||
},
|
||||
"CreatePointCache": {
|
||||
"enabled": true,
|
||||
"defaults": [
|
||||
"Main"
|
||||
]
|
||||
},
|
||||
"CreateRender": {
|
||||
"enabled": true,
|
||||
"defaults": [
|
||||
"Main"
|
||||
]
|
||||
},
|
||||
"CreateRenderSetup": {
|
||||
"enabled": true,
|
||||
"defaults": [
|
||||
"Main"
|
||||
]
|
||||
},
|
||||
"CreateReview": {
|
||||
"enabled": true,
|
||||
"defaults": [
|
||||
"Main"
|
||||
]
|
||||
},
|
||||
"CreateRig": {
|
||||
"enabled": true,
|
||||
"defaults": [
|
||||
"Main",
|
||||
"Sim",
|
||||
"Cloth"
|
||||
]
|
||||
},
|
||||
"CreateSetDress": {
|
||||
"enabled": true,
|
||||
"defaults": [
|
||||
"Main",
|
||||
"Anim"
|
||||
]
|
||||
},
|
||||
"CreateUnrealStaticMesh": {
|
||||
"enabled": true,
|
||||
"defaults": [
|
||||
"Main"
|
||||
]
|
||||
},
|
||||
"CreateVrayProxy": {
|
||||
"enabled": true,
|
||||
"defaults": [
|
||||
"Main"
|
||||
]
|
||||
},
|
||||
"CreateVRayScene": {
|
||||
"enabled": true,
|
||||
"defaults": [
|
||||
"Main"
|
||||
]
|
||||
},
|
||||
"CreateYetiRig": {
|
||||
"enabled": true,
|
||||
"defaults": [
|
||||
"Main"
|
||||
]
|
||||
}
|
||||
},
|
||||
"publish": {
|
||||
"CollectMayaRender": {
|
||||
"sync_workfile_version": false
|
||||
},
|
||||
"ValidateShaderName": {
|
||||
"enabled": false,
|
||||
"regex": "(?P<asset>.*)_(.*)_SHD"
|
||||
},
|
||||
"ValidateAttributes": {
|
||||
"enabled": false,
|
||||
"attributes": {}
|
||||
},
|
||||
"ValidateModelName": {
|
||||
"enabled": false,
|
||||
"material_file": {
|
||||
"windows": "",
|
||||
"darwin": "",
|
||||
"linux": ""
|
||||
},
|
||||
"regex": "(.*)_(\\\\d)*_(.*)_(GEO)"
|
||||
},
|
||||
"ValidateTransformNamingSuffix": {
|
||||
"enabled": true,
|
||||
"SUFFIX_NAMING_TABLE": {
|
||||
"mesh": [
|
||||
"_GEO",
|
||||
"_GES",
|
||||
"_GEP",
|
||||
"_OSD"
|
||||
],
|
||||
"nurbsCurve": [
|
||||
"_CRV"
|
||||
],
|
||||
"nurbsSurface": [
|
||||
"_NRB"
|
||||
],
|
||||
"locator": [
|
||||
"_LOC"
|
||||
],
|
||||
"group": [
|
||||
"_GRP"
|
||||
]
|
||||
},
|
||||
"ALLOW_IF_NOT_IN_SUFFIX_TABLE": true
|
||||
},
|
||||
"ValidateColorSets": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateMeshHasOverlappingUVs": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateMeshArnoldAttributes": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateMeshShaderConnections": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateMeshSingleUVSet": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateMeshHasUVs": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateMeshLaminaFaces": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateMeshNonManifold": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateMeshNormalsUnlocked": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateMeshUVSetMap1": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateMeshVerticesHaveEdges": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateNoAnimation": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateNoNamespace": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateNoNullTransforms": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateNoUnknownNodes": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateNodeNoGhosting": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateShapeDefaultNames": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateShapeRenderStats": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateTransformZero": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateCameraAttributes": {
|
||||
"enabled": false,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateAssemblyName": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateAssRelativePaths": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ExtractPlayblast": {
|
||||
"capture_preset": {
|
||||
"Codec": {
|
||||
"compression": "jpg",
|
||||
"format": "image",
|
||||
"quality": 95
|
||||
},
|
||||
"Display Options": {
|
||||
"background": [
|
||||
0.7,
|
||||
0.7,
|
||||
0.7
|
||||
],
|
||||
"backgroundBottom": [
|
||||
0.7,
|
||||
0.7,
|
||||
0.7
|
||||
],
|
||||
"backgroundTop": [
|
||||
0.7,
|
||||
0.7,
|
||||
0.7
|
||||
],
|
||||
"override_display": true
|
||||
},
|
||||
"Generic": {
|
||||
"isolate_view": true,
|
||||
"off_screen": true
|
||||
},
|
||||
"PanZoom": {
|
||||
"pan_zoom": true
|
||||
},
|
||||
"Renderer": {
|
||||
"rendererName": "vp2Renderer"
|
||||
},
|
||||
"Resolution": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"percent": 1.0,
|
||||
"mode": "Custom"
|
||||
},
|
||||
"Viewport Options": {
|
||||
"override_viewport_options": true,
|
||||
"displayLights": "default",
|
||||
"textureMaxResolution": 1024,
|
||||
"multiSample": 4,
|
||||
"shadows": true,
|
||||
"textures": true,
|
||||
"twoSidedLighting": true,
|
||||
"ssaoEnable": true,
|
||||
"cameras": false,
|
||||
"clipGhosts": false,
|
||||
"controlVertices": false,
|
||||
"deformers": false,
|
||||
"dimensions": false,
|
||||
"dynamicConstraints": false,
|
||||
"dynamics": false,
|
||||
"fluids": false,
|
||||
"follicles": false,
|
||||
"gpuCacheDisplayFilter": false,
|
||||
"greasePencils": false,
|
||||
"grid": false,
|
||||
"hairSystems": true,
|
||||
"handles": false,
|
||||
"hud": false,
|
||||
"hulls": false,
|
||||
"ikHandles": false,
|
||||
"imagePlane": true,
|
||||
"joints": false,
|
||||
"lights": false,
|
||||
"locators": false,
|
||||
"manipulators": false,
|
||||
"motionTrails": false,
|
||||
"nCloths": false,
|
||||
"nParticles": false,
|
||||
"nRigids": false,
|
||||
"nurbsCurves": false,
|
||||
"nurbsSurfaces": false,
|
||||
"particleInstancers": false,
|
||||
"pivots": false,
|
||||
"planes": false,
|
||||
"pluginShapes": false,
|
||||
"polymeshes": true,
|
||||
"strokes": false,
|
||||
"subdivSurfaces": false
|
||||
},
|
||||
"Camera Options": {
|
||||
"displayGateMask": false,
|
||||
"displayResolution": false,
|
||||
"displayFilmGate": false,
|
||||
"displayFieldChart": false,
|
||||
"displaySafeAction": false,
|
||||
"displaySafeTitle": false,
|
||||
"displayFilmPivot": false,
|
||||
"displayFilmOrigin": false,
|
||||
"overscan": 1.0
|
||||
}
|
||||
}
|
||||
},
|
||||
"ExtractCameraAlembic": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"active": true,
|
||||
"bake_attributes": []
|
||||
},
|
||||
"MayaSubmitDeadline": {
|
||||
"enabled": true,
|
||||
"tile_assembler_plugin": "DraftTileAssembler"
|
||||
}
|
||||
},
|
||||
"load": {
|
||||
"colors": {
|
||||
"model": [
|
||||
0.821,
|
||||
0.518,
|
||||
0.117
|
||||
],
|
||||
"rig": [
|
||||
0.144,
|
||||
0.443,
|
||||
0.463
|
||||
],
|
||||
"pointcache": [
|
||||
0.368,
|
||||
0.821,
|
||||
0.117
|
||||
],
|
||||
"animation": [
|
||||
0.368,
|
||||
0.821,
|
||||
0.117
|
||||
],
|
||||
"ass": [
|
||||
1.0,
|
||||
0.332,
|
||||
0.312
|
||||
],
|
||||
"camera": [
|
||||
0.447,
|
||||
0.312,
|
||||
1.0
|
||||
],
|
||||
"fbx": [
|
||||
1.0,
|
||||
0.931,
|
||||
0.312
|
||||
],
|
||||
"mayaAscii": [
|
||||
0.312,
|
||||
1.0,
|
||||
0.747
|
||||
],
|
||||
"setdress": [
|
||||
0.312,
|
||||
1.0,
|
||||
0.747
|
||||
],
|
||||
"layout": [
|
||||
0.312,
|
||||
1.0,
|
||||
0.747
|
||||
],
|
||||
"vdbcache": [
|
||||
0.312,
|
||||
1.0,
|
||||
0.428
|
||||
],
|
||||
"vrayproxy": [
|
||||
0.258,
|
||||
0.95,
|
||||
0.541
|
||||
],
|
||||
"yeticache": [
|
||||
0.2,
|
||||
0.8,
|
||||
0.3
|
||||
],
|
||||
"yetiRig": [
|
||||
0.0,
|
||||
0.8,
|
||||
0.5
|
||||
]
|
||||
}
|
||||
},
|
||||
"workfile_build": {
|
||||
"profiles": [
|
||||
{
|
||||
"tasks": [
|
||||
"Lighting"
|
||||
],
|
||||
"current_context": [
|
||||
{
|
||||
"subset_name_filters": [
|
||||
"\".+[Mm]ain\""
|
||||
],
|
||||
"families": [
|
||||
"model"
|
||||
],
|
||||
"repre_names": [
|
||||
"abc",
|
||||
"ma"
|
||||
],
|
||||
"loaders": [
|
||||
"ReferenceLoader"
|
||||
]
|
||||
},
|
||||
{
|
||||
"subset_name_filters": [],
|
||||
"families": [
|
||||
"animation",
|
||||
"pointcache"
|
||||
],
|
||||
"repre_names": [
|
||||
"abc"
|
||||
],
|
||||
"loaders": [
|
||||
"ReferenceLoader"
|
||||
]
|
||||
},
|
||||
{
|
||||
"subset_name_filters": [],
|
||||
"families": [
|
||||
"rendersetup"
|
||||
],
|
||||
"repre_names": [
|
||||
"json"
|
||||
],
|
||||
"loaders": [
|
||||
"RenderSetupLoader"
|
||||
]
|
||||
},
|
||||
{
|
||||
"subset_name_filters": [],
|
||||
"families": [
|
||||
"camera"
|
||||
],
|
||||
"repre_names": [
|
||||
"abc"
|
||||
],
|
||||
"loaders": [
|
||||
"ReferenceLoader"
|
||||
]
|
||||
}
|
||||
],
|
||||
"linked_assets": [
|
||||
{
|
||||
"subset_name_filters": [],
|
||||
"families": [
|
||||
"sedress"
|
||||
],
|
||||
"repre_names": [
|
||||
"ma"
|
||||
],
|
||||
"loaders": [
|
||||
"ReferenceLoader"
|
||||
]
|
||||
},
|
||||
{
|
||||
"subset_name_filters": [],
|
||||
"families": [
|
||||
"ArnoldStandin"
|
||||
],
|
||||
"repre_names": [
|
||||
"ass"
|
||||
],
|
||||
"loaders": [
|
||||
"assLoader"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"filters": {
|
||||
"preset 1": {
|
||||
"ValidateNoAnimation": false,
|
||||
"ValidateShapeDefaultNames": false
|
||||
},
|
||||
"preset 2": {
|
||||
"ValidateNoAnimation": false
|
||||
}
|
||||
}
|
||||
}
|
||||
181
openpype/settings/defaults/project_settings/nuke.json
Normal file
181
openpype/settings/defaults/project_settings/nuke.json
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
{
|
||||
"general": {
|
||||
"menu": {
|
||||
"create": "ctrl+shift+alt+c",
|
||||
"publish": "ctrl+alt+p",
|
||||
"load": "ctrl+alt+l",
|
||||
"manage": "ctrl+alt+m",
|
||||
"build_workfile": "ctrl+alt+b"
|
||||
}
|
||||
},
|
||||
"create": {
|
||||
"CreateWriteRender": {
|
||||
"fpath_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}"
|
||||
},
|
||||
"CreateWritePrerender": {
|
||||
"fpath_template": "{work}/prerenders/nuke/{subset}/{subset}.{frame}.{ext}"
|
||||
}
|
||||
},
|
||||
"publish": {
|
||||
"PreCollectNukeInstances": {
|
||||
"sync_workfile_version": true
|
||||
},
|
||||
"ValidateKnobs": {
|
||||
"enabled": false,
|
||||
"knobs": {
|
||||
"render": {
|
||||
"review": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"ValidateOutputResolution": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateGizmo": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateScript": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateNukeWriteBoundingBox": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ExtractThumbnail": {
|
||||
"enabled": true,
|
||||
"nodes": {
|
||||
"Reformat": [
|
||||
[
|
||||
"type",
|
||||
"to format"
|
||||
],
|
||||
[
|
||||
"format",
|
||||
"HD_1080"
|
||||
],
|
||||
[
|
||||
"filter",
|
||||
"Lanczos6"
|
||||
],
|
||||
[
|
||||
"black_outside",
|
||||
true
|
||||
],
|
||||
[
|
||||
"pbb",
|
||||
false
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"ExtractReviewDataLut": {
|
||||
"enabled": false
|
||||
},
|
||||
"ExtractReviewDataMov": {
|
||||
"enabled": true,
|
||||
"viewer_lut_raw": false
|
||||
},
|
||||
"ExtractSlateFrame": {
|
||||
"viewer_lut_raw": false
|
||||
},
|
||||
"NukeSubmitDeadline": {
|
||||
"deadline_priority": 50,
|
||||
"deadline_pool": "",
|
||||
"deadline_pool_secondary": "",
|
||||
"deadline_chunk_size": 1
|
||||
}
|
||||
},
|
||||
"load": {
|
||||
"LoadImage": {
|
||||
"enabled": true,
|
||||
"families": [
|
||||
"render2d",
|
||||
"source",
|
||||
"plate",
|
||||
"render",
|
||||
"prerender",
|
||||
"review",
|
||||
"image"
|
||||
],
|
||||
"representations": [
|
||||
"exr",
|
||||
"dpx",
|
||||
"jpg",
|
||||
"jpeg",
|
||||
"png",
|
||||
"psd"
|
||||
],
|
||||
"node_name_template": "{class_name}_{ext}"
|
||||
},
|
||||
"LoadMov": {
|
||||
"enabled": true,
|
||||
"families": [
|
||||
"source",
|
||||
"plate",
|
||||
"render",
|
||||
"prerender",
|
||||
"review"
|
||||
],
|
||||
"representations": [
|
||||
"mov",
|
||||
"review",
|
||||
"mp4",
|
||||
"h264"
|
||||
],
|
||||
"node_name_template": "{class_name}_{ext}"
|
||||
},
|
||||
"LoadSequence": {
|
||||
"enabled": true,
|
||||
"families": [
|
||||
"render2d",
|
||||
"source",
|
||||
"plate",
|
||||
"render",
|
||||
"prerender",
|
||||
"review"
|
||||
],
|
||||
"representations": [
|
||||
"exr",
|
||||
"dpx",
|
||||
"jpg",
|
||||
"jpeg",
|
||||
"png"
|
||||
],
|
||||
"node_name_template": "{class_name}_{ext}"
|
||||
}
|
||||
},
|
||||
"workfile_build": {
|
||||
"profiles": [
|
||||
{
|
||||
"tasks": [
|
||||
"compositing"
|
||||
],
|
||||
"current_context": [
|
||||
{
|
||||
"subset_name_filters": [],
|
||||
"families": [
|
||||
"render",
|
||||
"plate"
|
||||
],
|
||||
"repre_names": [
|
||||
"exr",
|
||||
"dpx"
|
||||
],
|
||||
"loaders": [
|
||||
"LoadSequence"
|
||||
]
|
||||
}
|
||||
],
|
||||
"linked_assets": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"filters": {}
|
||||
}
|
||||
20
openpype/settings/defaults/project_settings/resolve.json
Normal file
20
openpype/settings/defaults/project_settings/resolve.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"create": {
|
||||
"CreateShotClip": {
|
||||
"hierarchy": "{folder}/{sequence}",
|
||||
"clipRename": true,
|
||||
"clipName": "{track}{sequence}{shot}",
|
||||
"countFrom": 10,
|
||||
"countSteps": 10,
|
||||
"folder": "shots",
|
||||
"episode": "ep01",
|
||||
"sequence": "sq01",
|
||||
"track": "{_track_}",
|
||||
"shot": "sh###",
|
||||
"vSyncOn": false,
|
||||
"workfileFrameStart": 1001,
|
||||
"handleStart": 10,
|
||||
"handleEnd": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
{
|
||||
"create": {
|
||||
"create_workfile": {
|
||||
"name": "workfile",
|
||||
"label": "Workfile",
|
||||
"family": "workfile",
|
||||
"icon": "cube",
|
||||
"defaults": [
|
||||
"Main"
|
||||
],
|
||||
"help": "Working scene backup"
|
||||
},
|
||||
"create_model": {
|
||||
"name": "model",
|
||||
"label": "Model",
|
||||
"family": "model",
|
||||
"icon": "cube",
|
||||
"defaults": [
|
||||
"Main"
|
||||
],
|
||||
"help": "Polygonal static geometry"
|
||||
},
|
||||
"create_rig": {
|
||||
"name": "rig",
|
||||
"label": "Rig",
|
||||
"family": "rig",
|
||||
"icon": "wheelchair",
|
||||
"defaults": [
|
||||
"Main",
|
||||
"Cloth"
|
||||
],
|
||||
"help": "Artist-friendly rig with controls"
|
||||
},
|
||||
"create_pointcache": {
|
||||
"name": "pointcache",
|
||||
"label": "Pointcache",
|
||||
"family": "pointcache",
|
||||
"icon": "gears",
|
||||
"defaults": [
|
||||
"Main"
|
||||
],
|
||||
"help": "Alembic pointcache for animated data"
|
||||
},
|
||||
"create_plate": {
|
||||
"name": "plate",
|
||||
"label": "Plate",
|
||||
"family": "plate",
|
||||
"icon": "camera",
|
||||
"defaults": [
|
||||
"Main",
|
||||
"BG",
|
||||
"Animatic",
|
||||
"Reference",
|
||||
"Offline"
|
||||
],
|
||||
"help": "Footage for composting or reference"
|
||||
},
|
||||
"create_camera": {
|
||||
"name": "camera",
|
||||
"label": "Camera",
|
||||
"family": "camera",
|
||||
"icon": "camera",
|
||||
"defaults": [
|
||||
"Main"
|
||||
],
|
||||
"help": "video-camera"
|
||||
},
|
||||
"create_editorial": {
|
||||
"name": "editorial",
|
||||
"label": "Editorial",
|
||||
"family": "editorial",
|
||||
"icon": "image",
|
||||
"defaults": [
|
||||
"Main"
|
||||
],
|
||||
"help": "Editorial files to generate shots."
|
||||
},
|
||||
"create_image": {
|
||||
"name": "image",
|
||||
"label": "Image file",
|
||||
"family": "image",
|
||||
"icon": "image",
|
||||
"defaults": [
|
||||
"Reference",
|
||||
"Texture",
|
||||
"ConceptArt",
|
||||
"MattePaint"
|
||||
],
|
||||
"help": "Holder for all kinds of image data"
|
||||
},
|
||||
"create_matchmove": {
|
||||
"name": "matchmove",
|
||||
"label": "Matchmove Scripts",
|
||||
"family": "matchmove",
|
||||
"icon": "empire",
|
||||
"defaults": [
|
||||
"Camera",
|
||||
"Object",
|
||||
"Mocap"
|
||||
],
|
||||
"help": "Script exported from matchmoving application"
|
||||
},
|
||||
"__dynamic_keys_labels__": {
|
||||
"create_workfile": "Workfile",
|
||||
"create_model": "Model",
|
||||
"create_rig": "Rig",
|
||||
"create_pointcache": "Pointcache",
|
||||
"create_plate": "Plate",
|
||||
"create_camera": "Camera",
|
||||
"create_editorial": "Editorial",
|
||||
"create_image": "Image",
|
||||
"create_matchmove": "Matchmove"
|
||||
}
|
||||
},
|
||||
"publish": {
|
||||
"ExtractThumbnailSP": {
|
||||
"ffmpeg_args": {
|
||||
"input": [
|
||||
"gamma 2.2"
|
||||
],
|
||||
"output": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
6
openpype/settings/defaults/project_settings/unreal.json
Normal file
6
openpype/settings/defaults/project_settings/unreal.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"project_setup": {
|
||||
"dev_mode": true,
|
||||
"install_unreal_python_engine": false
|
||||
}
|
||||
}
|
||||
1179
openpype/settings/defaults/system_settings/applications.json
Normal file
1179
openpype/settings/defaults/system_settings/applications.json
Normal file
File diff suppressed because it is too large
Load diff
23
openpype/settings/defaults/system_settings/general.json
Normal file
23
openpype/settings/defaults/system_settings/general.json
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"studio_name": "Studio name",
|
||||
"studio_code": "stu",
|
||||
"environment": {
|
||||
"FFMPEG_PATH": {
|
||||
"windows": "{OPENPYPE_ROOT}/vendor/bin/ffmpeg_exec/windows/bin",
|
||||
"darwin": "{OPENPYPE_ROOT}/vendor/bin/ffmpeg_exec/darwin/bin",
|
||||
"linux": ":{OPENPYPE_ROOT}/vendor/bin/ffmpeg_exec/linux"
|
||||
},
|
||||
"OPENPYPE_OCIO_CONFIG": "{STUDIO_SOFT}/OpenColorIO-Configs",
|
||||
"__environment_keys__": {
|
||||
"global": [
|
||||
"FFMPEG_PATH",
|
||||
"OPENPYPE_OCIO_CONFIG"
|
||||
]
|
||||
}
|
||||
},
|
||||
"openpype_path": {
|
||||
"windows": [],
|
||||
"darwin": [],
|
||||
"linux": []
|
||||
}
|
||||
}
|
||||
172
openpype/settings/defaults/system_settings/modules.json
Normal file
172
openpype/settings/defaults/system_settings/modules.json
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
{
|
||||
"avalon": {
|
||||
"AVALON_TIMEOUT": 1000,
|
||||
"AVALON_THUMBNAIL_ROOT": {
|
||||
"windows": "",
|
||||
"darwin": "",
|
||||
"linux": ""
|
||||
}
|
||||
},
|
||||
"ftrack": {
|
||||
"enabled": true,
|
||||
"ftrack_server": "",
|
||||
"ftrack_actions_path": [],
|
||||
"ftrack_events_path": [],
|
||||
"intent": {
|
||||
"items": {
|
||||
"-": "-",
|
||||
"wip": "WIP",
|
||||
"final": "Final",
|
||||
"test": "Test"
|
||||
},
|
||||
"default": "-"
|
||||
},
|
||||
"custom_attributes": {
|
||||
"show": {
|
||||
"avalon_auto_sync": {
|
||||
"write_security_roles": [
|
||||
"API",
|
||||
"Administrator"
|
||||
],
|
||||
"read_security_roles": [
|
||||
"API",
|
||||
"Administrator"
|
||||
]
|
||||
},
|
||||
"library_project": {
|
||||
"write_security_roles": [
|
||||
"API",
|
||||
"Administrator"
|
||||
],
|
||||
"read_security_roles": [
|
||||
"API",
|
||||
"Administrator"
|
||||
]
|
||||
},
|
||||
"applications": {
|
||||
"write_security_roles": [
|
||||
"API",
|
||||
"Administrator",
|
||||
"Pypeclub"
|
||||
],
|
||||
"read_security_roles": [
|
||||
"API",
|
||||
"Administrator",
|
||||
"Pypeclub"
|
||||
]
|
||||
}
|
||||
},
|
||||
"is_hierarchical": {
|
||||
"tools_env": {
|
||||
"write_security_roles": [
|
||||
"API",
|
||||
"Administrator",
|
||||
"Pypeclub"
|
||||
],
|
||||
"read_security_roles": [
|
||||
"API",
|
||||
"Administrator",
|
||||
"Pypeclub"
|
||||
]
|
||||
},
|
||||
"avalon_mongo_id": {
|
||||
"write_security_roles": [
|
||||
"API",
|
||||
"Administrator",
|
||||
"Pypeclub"
|
||||
],
|
||||
"read_security_roles": [
|
||||
"API",
|
||||
"Administrator",
|
||||
"Pypeclub"
|
||||
]
|
||||
},
|
||||
"fps": {
|
||||
"write_security_roles": [],
|
||||
"read_security_roles": []
|
||||
},
|
||||
"frameStart": {
|
||||
"write_security_roles": [],
|
||||
"read_security_roles": []
|
||||
},
|
||||
"frameEnd": {
|
||||
"write_security_roles": [],
|
||||
"read_security_roles": []
|
||||
},
|
||||
"clipIn": {
|
||||
"write_security_roles": [],
|
||||
"read_security_roles": []
|
||||
},
|
||||
"clipOut": {
|
||||
"write_security_roles": [],
|
||||
"read_security_roles": []
|
||||
},
|
||||
"handleStart": {
|
||||
"write_security_roles": [],
|
||||
"read_security_roles": []
|
||||
},
|
||||
"handleEnd": {
|
||||
"write_security_roles": [],
|
||||
"read_security_roles": []
|
||||
},
|
||||
"resolutionWidth": {
|
||||
"write_security_roles": [],
|
||||
"read_security_roles": []
|
||||
},
|
||||
"resolutionHeight": {
|
||||
"write_security_roles": [],
|
||||
"read_security_roles": []
|
||||
},
|
||||
"pixelAspect": {
|
||||
"write_security_roles": [],
|
||||
"read_security_roles": []
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"timers_manager": {
|
||||
"enabled": true,
|
||||
"full_time": 15.0,
|
||||
"message_time": 0.5
|
||||
},
|
||||
"clockify": {
|
||||
"enabled": false,
|
||||
"workspace_name": ""
|
||||
},
|
||||
"sync_server": {
|
||||
"enabled": false
|
||||
},
|
||||
"deadline": {
|
||||
"enabled": true,
|
||||
"DEADLINE_REST_URL": "http://localhost:8082"
|
||||
},
|
||||
"muster": {
|
||||
"enabled": false,
|
||||
"MUSTER_REST_URL": "http://127.0.0.1:9890",
|
||||
"templates_mapping": {
|
||||
"file_layers": 7,
|
||||
"mentalray": 2,
|
||||
"mentalray_sf": 6,
|
||||
"redshift": 55,
|
||||
"renderman": 29,
|
||||
"software": 1,
|
||||
"software_sf": 5,
|
||||
"turtle": 10,
|
||||
"vector": 4,
|
||||
"vray": 37,
|
||||
"ffmpeg": 48
|
||||
}
|
||||
},
|
||||
"log_viewer": {
|
||||
"enabled": true
|
||||
},
|
||||
"user": {
|
||||
"enabled": true
|
||||
},
|
||||
"standalonepublish_tool": {
|
||||
"enabled": true
|
||||
},
|
||||
"idle_manager": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
53
openpype/settings/defaults/system_settings/tools.json
Normal file
53
openpype/settings/defaults/system_settings/tools.json
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
"tool_groups": {
|
||||
"mtoa": {
|
||||
"environment": {
|
||||
"MTOA": "{STUDIO_SOFTWARE}/arnold/mtoa_{MAYA_VERSION}_{MTOA_VERSION}",
|
||||
"MAYA_RENDER_DESC_PATH": "{MTOA}",
|
||||
"MAYA_MODULE_PATH": "{MTOA}",
|
||||
"ARNOLD_PLUGIN_PATH": "{MTOA}/shaders",
|
||||
"MTOA_EXTENSIONS_PATH": {
|
||||
"darwin": "{MTOA}/extensions",
|
||||
"linux": "{MTOA}/extensions",
|
||||
"windows": "{MTOA}/extensions"
|
||||
},
|
||||
"MTOA_EXTENSIONS": {
|
||||
"darwin": "{MTOA}/extensions",
|
||||
"linux": "{MTOA}/extensions",
|
||||
"windows": "{MTOA}/extensions"
|
||||
},
|
||||
"DYLD_LIBRARY_PATH": {
|
||||
"darwin": "{MTOA}/bin"
|
||||
},
|
||||
"PATH": {
|
||||
"windows": "{PATH};{MTOA}/bin"
|
||||
}
|
||||
},
|
||||
"variants": {
|
||||
"3-2": {
|
||||
"MTOA_VERSION": "3.2"
|
||||
},
|
||||
"3-1": {
|
||||
"MTOA_VERSION": "3.1"
|
||||
},
|
||||
"__dynamic_keys_labels__": {
|
||||
"3-2": "3.2",
|
||||
"3-1": "3.2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"vray": {
|
||||
"environment": {},
|
||||
"variants": {}
|
||||
},
|
||||
"yeti": {
|
||||
"environment": {},
|
||||
"variants": {}
|
||||
},
|
||||
"__dynamic_keys_labels__": {
|
||||
"mtoa": "Autodesk Arnold",
|
||||
"vray": "Chaos Group Vray",
|
||||
"yeti": "Pergrine Labs Yeti"
|
||||
}
|
||||
}
|
||||
}
|
||||
160
openpype/settings/entities/__init__.py
Normal file
160
openpype/settings/entities/__init__.py
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
"""OpenPype Settings
|
||||
|
||||
Settings define how openpype and it's modules behave. They became main
|
||||
component of dynamism.
|
||||
|
||||
OpenPype settings (ATM) have 3 layers:
|
||||
1.) Defaults - defined in code
|
||||
2.) Studio overrides - values that are applied on default that may modify only
|
||||
some values or None, result can be called "studio settings"
|
||||
3.) Project overrides - values that are applied on studio settings, may modify
|
||||
some values or None and may modify values that are not modified in studio
|
||||
overrides
|
||||
|
||||
To be able do these overrides it is required to store metadata defying which
|
||||
data are applied and how. Because of that it is not possible to modify
|
||||
overrides manually and expect it would work right.
|
||||
|
||||
Structure of settings is defined with schemas. Schemas have defined structure
|
||||
and possible types with possible attributes (Schemas and their description
|
||||
can be found in "./schemas/README.md").
|
||||
|
||||
To modify settings it's recommended to use UI settings tool which can easily
|
||||
visuallise how values are applied.
|
||||
|
||||
With help of setting entities it is possible to modify settings from code.
|
||||
|
||||
OpenPype has (ATM) 2 types of settings:
|
||||
1.) System settings - global system settings, don't have project overrides
|
||||
2.) Project settings - project specific settings
|
||||
|
||||
Startpoint is root entity that cares about access to other setting entities
|
||||
in their scope. To be able work with entities it is required to understand
|
||||
setting schemas and their structure. It is possible to work with dictionary
|
||||
and list entities as with standard python objects.
|
||||
|
||||
```python
|
||||
# Create an object of system settings.
|
||||
system_settings = SystemSettings()
|
||||
|
||||
# How to get value of entity
|
||||
print(system_settings["general"]["studio_name"].value)
|
||||
|
||||
>>> TestStudio Name
|
||||
|
||||
# How to set value
|
||||
# Variant 1
|
||||
system_settings["general"]["studio_name"] = "StudioidutS"
|
||||
# Variant 2
|
||||
system_settings["general"]["studio_name"].set("StudioidutS")
|
||||
|
||||
print(system_settings["general"]["studio_name"].value)
|
||||
>>> StudioidutS
|
||||
```
|
||||
"""
|
||||
|
||||
from .exceptions import (
|
||||
SchemaError,
|
||||
DefaultsNotDefined,
|
||||
StudioDefaultsNotDefined,
|
||||
InvalidValueType,
|
||||
InvalidKeySymbols,
|
||||
SchemaMissingFileInfo,
|
||||
SchemeGroupHierarchyBug,
|
||||
SchemaDuplicatedKeys,
|
||||
SchemaDuplicatedEnvGroupKeys,
|
||||
SchemaTemplateMissingKeys
|
||||
)
|
||||
from .lib import (
|
||||
NOT_SET,
|
||||
OverrideState
|
||||
)
|
||||
from .base_entity import (
|
||||
BaseEntity,
|
||||
GUIEntity,
|
||||
BaseItemEntity,
|
||||
ItemEntity
|
||||
)
|
||||
|
||||
from .root_entities import (
|
||||
SystemSettings,
|
||||
ProjectSettings
|
||||
)
|
||||
|
||||
from .item_entities import (
|
||||
PathEntity,
|
||||
ListStrictEntity
|
||||
)
|
||||
|
||||
from .input_entities import (
|
||||
EndpointEntity,
|
||||
InputEntity,
|
||||
|
||||
NumberEntity,
|
||||
BoolEntity,
|
||||
TextEntity,
|
||||
PathInput,
|
||||
RawJsonEntity
|
||||
)
|
||||
|
||||
from .enum_entity import (
|
||||
BaseEnumEntity,
|
||||
EnumEntity,
|
||||
AppsEnumEntity,
|
||||
ToolsEnumEntity
|
||||
)
|
||||
|
||||
from .list_entity import ListEntity
|
||||
from .dict_immutable_keys_entity import DictImmutableKeysEntity
|
||||
from .dict_mutable_keys_entity import DictMutableKeysEntity
|
||||
|
||||
from .anatomy_entities import AnatomyEntity
|
||||
|
||||
|
||||
__all__ = (
|
||||
"DefaultsNotDefined",
|
||||
"StudioDefaultsNotDefined",
|
||||
"InvalidValueType",
|
||||
"InvalidKeySymbols",
|
||||
"SchemaMissingFileInfo",
|
||||
"SchemeGroupHierarchyBug",
|
||||
"SchemaDuplicatedKeys",
|
||||
"SchemaDuplicatedEnvGroupKeys",
|
||||
"SchemaTemplateMissingKeys",
|
||||
|
||||
"NOT_SET",
|
||||
"OverrideState",
|
||||
|
||||
"BaseEntity",
|
||||
"GUIEntity",
|
||||
"BaseItemEntity",
|
||||
"ItemEntity",
|
||||
|
||||
"SystemSettings",
|
||||
"ProjectSettings",
|
||||
|
||||
"PathEntity",
|
||||
"ListStrictEntity",
|
||||
|
||||
"EndpointEntity",
|
||||
"InputEntity",
|
||||
|
||||
"NumberEntity",
|
||||
"BoolEntity",
|
||||
"TextEntity",
|
||||
"PathInput",
|
||||
"RawJsonEntity",
|
||||
|
||||
"BaseEnumEntity",
|
||||
"EnumEntity",
|
||||
"AppsEnumEntity",
|
||||
"ToolsEnumEntity",
|
||||
|
||||
"ListEntity",
|
||||
|
||||
"DictImmutableKeysEntity",
|
||||
|
||||
"DictMutableKeysEntity",
|
||||
|
||||
"AnatomyEntity"
|
||||
)
|
||||
25
openpype/settings/entities/anatomy_entities.py
Normal file
25
openpype/settings/entities/anatomy_entities.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
from .dict_immutable_keys_entity import DictImmutableKeysEntity
|
||||
from .lib import OverrideState
|
||||
|
||||
|
||||
class AnatomyEntity(DictImmutableKeysEntity):
|
||||
schema_types = ["anatomy"]
|
||||
|
||||
def _update_current_metadata(self):
|
||||
if self._override_state is OverrideState.PROJECT:
|
||||
return {}
|
||||
return super(AnatomyEntity, self)._update_current_metadata()
|
||||
|
||||
def set_override_state(self, *args, **kwargs):
|
||||
super(AnatomyEntity, self).set_override_state(*args, **kwargs)
|
||||
if self._override_state is OverrideState.PROJECT:
|
||||
for child_obj in self.non_gui_children.values():
|
||||
if not child_obj.has_project_override:
|
||||
self.add_to_project_override()
|
||||
break
|
||||
|
||||
def on_child_change(self, child_obj):
|
||||
if self._override_state is OverrideState.PROJECT:
|
||||
if not child_obj.has_project_override:
|
||||
child_obj.add_to_project_override()
|
||||
return super(AnatomyEntity, self).on_child_change(child_obj)
|
||||
874
openpype/settings/entities/base_entity.py
Normal file
874
openpype/settings/entities/base_entity.py
Normal file
|
|
@ -0,0 +1,874 @@
|
|||
from uuid import uuid4
|
||||
from abc import ABCMeta, abstractmethod, abstractproperty
|
||||
|
||||
import six
|
||||
|
||||
from .lib import (
|
||||
NOT_SET,
|
||||
OverrideState
|
||||
)
|
||||
|
||||
from .exceptions import (
|
||||
InvalidValueType,
|
||||
SchemeGroupHierarchyBug,
|
||||
EntitySchemaError
|
||||
)
|
||||
|
||||
from openpype.lib import PypeLogger
|
||||
|
||||
|
||||
@six.add_metaclass(ABCMeta)
|
||||
class BaseEntity:
|
||||
"""Base entity class for Setting's item type workflow.
|
||||
|
||||
Args:
|
||||
schema_data (dict): Schema data that defines entity behavior.
|
||||
"""
|
||||
|
||||
def __init__(self, schema_data, *args, **kwargs):
|
||||
self.schema_data = schema_data
|
||||
|
||||
# Entity id
|
||||
self._id = uuid4()
|
||||
|
||||
def __hash__(self):
|
||||
"""Make entity hashable by it's id.
|
||||
|
||||
Helps to store entities as keys in dictionary.
|
||||
"""
|
||||
return self.id
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
"""Unified identifier of an entity."""
|
||||
return self._id
|
||||
|
||||
@abstractproperty
|
||||
def gui_type(self):
|
||||
"""Is entity GUI type entity."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def schema_validations(self):
|
||||
"""Validation of schema."""
|
||||
pass
|
||||
|
||||
|
||||
class GUIEntity(BaseEntity):
|
||||
"""Entity without any specific logic that should be handled only in GUI."""
|
||||
gui_type = True
|
||||
|
||||
schema_types = ["separator", "splitter", "label"]
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.schema_data[key]
|
||||
|
||||
def schema_validations(self):
|
||||
"""TODO validate GUI schemas."""
|
||||
pass
|
||||
|
||||
|
||||
class BaseItemEntity(BaseEntity):
|
||||
"""Base of item entity that is not only for GUI but can modify values.
|
||||
|
||||
Defines minimum attributes of all entities that are not `gui_type`.
|
||||
|
||||
Args:
|
||||
schema_data (dict): Schema data that defines entity behavior.
|
||||
"""
|
||||
gui_type = False
|
||||
|
||||
def __init__(self, schema_data):
|
||||
super(BaseItemEntity, self).__init__(schema_data)
|
||||
|
||||
# Parent entity
|
||||
self.parent = None
|
||||
|
||||
# Entity is dynamically created (in list or dict with mutable keys)
|
||||
# - can be also dynamically removed
|
||||
self.is_dynamic_item = False
|
||||
|
||||
# Log object created on demand with `log` attribute
|
||||
self._log = None
|
||||
|
||||
# Item path attribute (may be filled or be dynamic)
|
||||
self._path = None
|
||||
|
||||
# These should be set on initialization and not change then
|
||||
self.valid_value_types = getattr(self, "valid_value_types", NOT_SET)
|
||||
self.value_on_not_set = getattr(self, "value_on_not_set", NOT_SET)
|
||||
|
||||
# Entity represents group entity
|
||||
# - all children entities will be saved on modification of overrides
|
||||
self.is_group = False
|
||||
# Entity's value will be stored into file with name of it's key
|
||||
self.is_file = False
|
||||
# Reference to parent entity which has `is_group` == True
|
||||
# - stays as None if none of parents is group
|
||||
self.group_item = None
|
||||
# Reference to parent entity which has `is_file` == True
|
||||
self.file_item = None
|
||||
# Reference to `RootEntity`
|
||||
self.root_item = None
|
||||
|
||||
# Entity is in hierarchy of dynamically created entity
|
||||
self.is_in_dynamic_item = False
|
||||
|
||||
# Entity will save metadata about environments
|
||||
# - this is current possible only for RawJsonEnity
|
||||
self.is_env_group = False
|
||||
# Key of environment group key must be unique across system settings
|
||||
self.env_group_key = None
|
||||
|
||||
# Roles of an entity
|
||||
self.roles = None
|
||||
|
||||
# Key must be specified in schema data otherwise won't work as expected
|
||||
self.require_key = True
|
||||
|
||||
# Key and label of an entity
|
||||
self.key = None
|
||||
self.label = None
|
||||
|
||||
# Override state defines which values are used, saved and how.
|
||||
# TODO convert to private attribute
|
||||
self._override_state = OverrideState.NOT_DEFINED
|
||||
|
||||
# These attributes may change values during existence of an object
|
||||
# Default value, studio override values and project override values
|
||||
# - these should be set only with `update_default_value` etc.
|
||||
# TODO convert to private attributes
|
||||
self._default_value = NOT_SET
|
||||
self._studio_override_value = NOT_SET
|
||||
self._project_override_value = NOT_SET
|
||||
|
||||
# Entity has set `_default_value` (is not NOT_SET)
|
||||
self.has_default_value = False
|
||||
|
||||
# Entity is marked as it contain studio override data so it's value
|
||||
# will be stored to studio overrides. This is relevant attribute
|
||||
# only if current override state is set to STUDIO.
|
||||
self._has_studio_override = False
|
||||
# Entity has set `_studio_override_value` (is not NOT_SET)
|
||||
self.had_studio_override = False
|
||||
|
||||
# Entity is marked as it contain project override data so it's value
|
||||
# will be stored to project overrides. This is relevant attribute
|
||||
# only if current override state is set to PROJECT.
|
||||
self._has_project_override = False
|
||||
# Entity has set `_project_override_value` (is not NOT_SET)
|
||||
self.had_project_override = False
|
||||
|
||||
# Callbacks that are called on change.
|
||||
# - main current purspose is to register GUI callbacks
|
||||
self.on_change_callbacks = []
|
||||
|
||||
roles = schema_data.get("roles")
|
||||
if roles is None:
|
||||
roles = []
|
||||
elif not isinstance(roles, list):
|
||||
roles = [roles]
|
||||
self.roles = roles
|
||||
|
||||
@property
|
||||
def has_studio_override(self):
|
||||
"""Says if entity or it's children has studio overrides."""
|
||||
if self._override_state >= OverrideState.STUDIO:
|
||||
return self._has_studio_override
|
||||
return False
|
||||
|
||||
@property
|
||||
def has_project_override(self):
|
||||
"""Says if entity or it's children has project overrides."""
|
||||
if self._override_state >= OverrideState.PROJECT:
|
||||
return self._has_project_override
|
||||
return False
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
"""Full path of an entity in settings hierarchy.
|
||||
|
||||
It is not possible to use this attribute during initialization because
|
||||
initialization happens before entity is added to parent's children.
|
||||
"""
|
||||
if self._path is not None:
|
||||
return self._path
|
||||
|
||||
path = self.parent.get_child_path(self)
|
||||
if not self.is_in_dynamic_item and not self.is_dynamic_item:
|
||||
self._path = path
|
||||
return path
|
||||
|
||||
@abstractmethod
|
||||
def get_child_path(self, child_entity):
|
||||
"""Return path for a direct child entity."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_entity_from_path(self, path):
|
||||
"""Return system settings entity."""
|
||||
pass
|
||||
|
||||
def schema_validations(self):
|
||||
"""Validate schema of entity and it's hierachy.
|
||||
|
||||
Contain default validations same for all entities.
|
||||
"""
|
||||
# Entity must have defined valid value types.
|
||||
if self.valid_value_types is NOT_SET:
|
||||
raise EntitySchemaError(
|
||||
self, "Attribute `valid_value_types` is not filled."
|
||||
)
|
||||
|
||||
# Check if entity has defined key when is required.
|
||||
if self.require_key and not self.key:
|
||||
error_msg = "Missing \"key\" in schema data. {}".format(
|
||||
str(self.schema_data).replace("'", '"')
|
||||
)
|
||||
raise EntitySchemaError(self, error_msg)
|
||||
|
||||
# Group entity must have defined label. (UI specific)
|
||||
# QUESTION this should not be required?
|
||||
if not self.label and self.is_group:
|
||||
raise EntitySchemaError(
|
||||
self, "Item is set as `is_group` but has empty `label`."
|
||||
)
|
||||
|
||||
# Group item can be only once in on hierarchy branch.
|
||||
if self.is_group and self.group_item:
|
||||
raise SchemeGroupHierarchyBug(self)
|
||||
|
||||
# Validate that env group entities will be stored into file.
|
||||
# - env group entities must store metadata which is not possible if
|
||||
# metadata would be outside of file
|
||||
if not self.file_item and self.is_env_group:
|
||||
reason = (
|
||||
"Environment item is not inside file"
|
||||
" item so can't store metadata for defaults."
|
||||
)
|
||||
raise EntitySchemaError(self, reason)
|
||||
|
||||
# Dynamic items must not have defined labels. (UI specific)
|
||||
if self.label and self.is_dynamic_item:
|
||||
raise EntitySchemaError(
|
||||
self, "Item has set label but is used as dynamic item."
|
||||
)
|
||||
|
||||
# Dynamic items or items in dynamic item must not have set `is_group`
|
||||
if self.is_group and (self.is_dynamic_item or self.is_in_dynamic_item):
|
||||
raise EntitySchemaError(
|
||||
self, "Dynamic entity has set `is_group` to true."
|
||||
)
|
||||
|
||||
@abstractmethod
|
||||
def set_override_state(self, state):
|
||||
"""Set override state and trigger it on children.
|
||||
|
||||
Method discard all changes in hierarchy and use values, metadata
|
||||
and all kind of values for defined override state. May be used to
|
||||
apply updated values (default, studio overrides, project overrides).
|
||||
|
||||
Should start on root entity and when triggered then must be called on
|
||||
all entities in hierarchy.
|
||||
|
||||
Args:
|
||||
state (OverrideState): State to which should be data changed.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def on_change(self):
|
||||
"""Trigger change callbacks and tell parent that has changed.
|
||||
|
||||
Can be any kind of change. Value has changed, has studio overrides
|
||||
changed from True to False, etc.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def on_child_change(self, child_entity):
|
||||
"""Triggered by children when they've changed.
|
||||
|
||||
Args:
|
||||
child_entity (BaseItemEntity): Direct child entity that has
|
||||
changed.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def set(self, value):
|
||||
"""Set value of entity.
|
||||
|
||||
Args:
|
||||
value (Any): Setter of value for this entity.
|
||||
"""
|
||||
pass
|
||||
|
||||
def is_value_valid_type(self, value):
|
||||
"""Validate passed value type by entity's defined valid types.
|
||||
|
||||
Returns:
|
||||
bool: True if value is in entity's defined types.
|
||||
"""
|
||||
return isinstance(value, self.valid_value_types)
|
||||
|
||||
def _validate_value_type(self, value):
|
||||
"""Validate entered value.
|
||||
|
||||
Raises:
|
||||
InvalidValueType: If value's type is not valid by entity's
|
||||
definition.
|
||||
"""
|
||||
if self.is_value_valid_type(value):
|
||||
return
|
||||
|
||||
raise InvalidValueType(self.valid_value_types, type(value), self.path)
|
||||
|
||||
def _convert_to_valid_type(self, value):
|
||||
"""Private method of entity to convert value.
|
||||
|
||||
NOTE: Method is not abstract as more entities won't have implemented
|
||||
logic inside.
|
||||
|
||||
Must return NOT_SET if can't convert the value.
|
||||
"""
|
||||
return NOT_SET
|
||||
|
||||
def convert_to_valid_type(self, value):
|
||||
"""Check value type with possibility of conversion to valid.
|
||||
|
||||
If entered value has right type than is returned as it is. otherwise
|
||||
is used privete method of entity to try convert.
|
||||
|
||||
Raises:
|
||||
InvalidValueType: If value's type is not valid by entity's
|
||||
definition and can't be converted by entity logic.
|
||||
"""
|
||||
#
|
||||
if self.is_value_valid_type(value):
|
||||
return value
|
||||
|
||||
new_value = self._convert_to_valid_type(value)
|
||||
if new_value is not NOT_SET and self.is_value_valid_type(new_value):
|
||||
return new_value
|
||||
|
||||
raise InvalidValueType(self.valid_value_types, type(value), self.path)
|
||||
|
||||
# TODO convert to private method
|
||||
def _check_update_value(self, value, value_source):
|
||||
"""Validation of value on update methods.
|
||||
|
||||
Update methods update data from currently saved settings so it is
|
||||
possible to have invalid type mainly during development.
|
||||
|
||||
Args:
|
||||
value (Any): Value that got to update method.
|
||||
value_source (str): Source update method. Is used for logging and
|
||||
is not used as part of logic ("default", "studio override",
|
||||
"project override").
|
||||
|
||||
Returns:
|
||||
Any: Return value itself if has valid type.
|
||||
NOT_SET: If value has invalid type.
|
||||
"""
|
||||
# Nothing to validate if is NOT_SET
|
||||
if value is NOT_SET:
|
||||
return value
|
||||
|
||||
try:
|
||||
new_value = self.convert_to_valid_type(value)
|
||||
except InvalidValueType:
|
||||
new_value = NOT_SET
|
||||
|
||||
if new_value is not NOT_SET:
|
||||
return new_value
|
||||
|
||||
# Warning log about invalid value type.
|
||||
self.log.warning(
|
||||
(
|
||||
"{} Got invalid value type for {} values."
|
||||
" Expected types: {} | Got Type: {} | Value: \"{}\""
|
||||
).format(
|
||||
self.path, value_source,
|
||||
self.valid_value_types, type(value), str(value)
|
||||
)
|
||||
)
|
||||
return NOT_SET
|
||||
|
||||
def available_for_role(self, role_name=None):
|
||||
"""Is entity valid for role.
|
||||
|
||||
Args:
|
||||
role_name (str): Name of role that will be validated. Entity's
|
||||
`user_role` attribute is used if not defined.
|
||||
|
||||
Returns:
|
||||
bool: True if is available for role.
|
||||
"""
|
||||
if not self.roles:
|
||||
return True
|
||||
if role_name is None:
|
||||
role_name = self.user_role
|
||||
return role_name in self.roles
|
||||
|
||||
@property
|
||||
def user_role(self):
|
||||
"""Entity is using user role.
|
||||
|
||||
Returns:
|
||||
str: user role as string.
|
||||
|
||||
"""
|
||||
return self.parent.user_role
|
||||
|
||||
@property
|
||||
def log(self):
|
||||
"""Auto created logger for debugging or warnings."""
|
||||
if self._log is None:
|
||||
self._log = PypeLogger.get_logger(self.__class__.__name__)
|
||||
return self._log
|
||||
|
||||
@abstractproperty
|
||||
def schema_types(self):
|
||||
pass
|
||||
|
||||
@abstractproperty
|
||||
def has_unsaved_changes(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def settings_value(self):
|
||||
"""Value of an item without key."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def save(self):
|
||||
"""Save data for current state."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def _item_initalization(self):
|
||||
"""Entity specific initialization process."""
|
||||
pass
|
||||
|
||||
@abstractproperty
|
||||
def value(self):
|
||||
"""Value of entity without metadata."""
|
||||
pass
|
||||
|
||||
@property
|
||||
def can_discard_changes(self):
|
||||
"""Result defines if `discard_changes` will be processed.
|
||||
|
||||
Also can be used as validation before the method is called.
|
||||
"""
|
||||
return self.has_unsaved_changes
|
||||
|
||||
@property
|
||||
def can_add_to_studio_default(self):
|
||||
"""Result defines if `add_to_studio_default` will be processed.
|
||||
|
||||
Also can be used as validation before the method is called.
|
||||
"""
|
||||
if self._override_state is not OverrideState.STUDIO:
|
||||
return False
|
||||
|
||||
if self.is_dynamic_item or self.is_in_dynamic_item:
|
||||
return False
|
||||
|
||||
# Skip if entity is under group
|
||||
if self.group_item:
|
||||
return False
|
||||
|
||||
# Skip if is group and any children is already marked with studio
|
||||
# overrides
|
||||
if self.is_group and self.has_studio_override:
|
||||
return False
|
||||
return True
|
||||
|
||||
@property
|
||||
def can_remove_from_studio_default(self):
|
||||
"""Result defines if `remove_from_studio_default` can be triggered.
|
||||
|
||||
This can be also used as validation before the method is called.
|
||||
"""
|
||||
if self._override_state is not OverrideState.STUDIO:
|
||||
return False
|
||||
|
||||
if self.is_dynamic_item or self.is_in_dynamic_item:
|
||||
return False
|
||||
|
||||
if not self.has_studio_override:
|
||||
return False
|
||||
return True
|
||||
|
||||
@property
|
||||
def can_add_to_project_override(self):
|
||||
"""Result defines if `add_to_project_override` can be triggered.
|
||||
|
||||
Also can be used as validation before the method is called.
|
||||
"""
|
||||
if self.is_dynamic_item or self.is_in_dynamic_item:
|
||||
return False
|
||||
|
||||
# Show only when project overrides are set
|
||||
if self._override_state is not OverrideState.PROJECT:
|
||||
return False
|
||||
|
||||
# Do not show on items under group item
|
||||
if self.group_item:
|
||||
return False
|
||||
|
||||
# Skip if already is marked to save project overrides
|
||||
if self.is_group and self.has_project_override:
|
||||
return False
|
||||
return True
|
||||
|
||||
@property
|
||||
def can_remove_from_project_override(self):
|
||||
"""Result defines if `remove_from_project_override` can be triggered.
|
||||
|
||||
This can be also used as validation before the method is called.
|
||||
"""
|
||||
if self.is_dynamic_item or self.is_in_dynamic_item:
|
||||
return False
|
||||
|
||||
if self._override_state is not OverrideState.PROJECT:
|
||||
return False
|
||||
|
||||
# Dynamic items can't have these actions
|
||||
if self.is_dynamic_item or self.is_in_dynamic_item:
|
||||
return False
|
||||
|
||||
if not self.has_project_override:
|
||||
return False
|
||||
return True
|
||||
|
||||
def discard_changes(self, on_change_trigger=None):
|
||||
"""Discard changes on entity and it's children.
|
||||
|
||||
Reset all values to same values as had when `set_override_state` was
|
||||
called last time.
|
||||
|
||||
Must not affect `had_studio_override` value or `had_project_override`
|
||||
value. It must be marked that there are keys/values which are not in
|
||||
defaults or overrides.
|
||||
|
||||
Won't affect if will be stored as overrides if entity is under
|
||||
group entity in hierarchy.
|
||||
|
||||
This is wrapper method that handles on_change callbacks only when all
|
||||
`_discard_changes` on all children happened. That is important as
|
||||
value changes may trigger change callbacks that must be ignored.
|
||||
Callbacks are triggered by entity where method was called.
|
||||
|
||||
Args:
|
||||
on_change_trigger (list): Callbacks of `on_change` should be stored
|
||||
to trigger them afterwards.
|
||||
"""
|
||||
initialized = False
|
||||
if on_change_trigger is None:
|
||||
if not self.can_discard_changes:
|
||||
return
|
||||
|
||||
initialized = True
|
||||
on_change_trigger = []
|
||||
|
||||
self._discard_changes(on_change_trigger)
|
||||
|
||||
if initialized:
|
||||
for callback in on_change_trigger:
|
||||
callback()
|
||||
|
||||
@abstractmethod
|
||||
def _discard_changes(self, on_change_trigger):
|
||||
"""Entity's implementation to discard all changes made by user."""
|
||||
pass
|
||||
|
||||
def add_to_studio_default(self, on_change_trigger=None):
|
||||
initialized = False
|
||||
if on_change_trigger is None:
|
||||
if not self.can_add_to_studio_default:
|
||||
return
|
||||
|
||||
initialized = True
|
||||
on_change_trigger = []
|
||||
|
||||
self._add_to_studio_default(on_change_trigger)
|
||||
|
||||
if initialized:
|
||||
for callback in on_change_trigger:
|
||||
callback()
|
||||
|
||||
@abstractmethod
|
||||
def _add_to_studio_default(self, on_change_trigger):
|
||||
"""Item's implementation to set current values as studio's overrides.
|
||||
|
||||
Mark item and it's children as they have studio overrides.
|
||||
"""
|
||||
pass
|
||||
|
||||
def remove_from_studio_default(self, on_change_trigger=None):
|
||||
"""Remove studio overrides from entity and it's children.
|
||||
|
||||
Reset values to openpype's default and mark entity to not store values
|
||||
as studio overrides if entity is not under group.
|
||||
|
||||
This is wrapper method that handles on_change callbacks only when all
|
||||
`_remove_from_studio_default` on all children happened. That is
|
||||
important as value changes may trigger change callbacks that must be
|
||||
ignored. Callbacks are triggered by entity where method was called.
|
||||
|
||||
Args:
|
||||
on_change_trigger (list): Callbacks of `on_change` should be stored
|
||||
to trigger them afterwards.
|
||||
"""
|
||||
initialized = False
|
||||
if on_change_trigger is None:
|
||||
if not self.can_remove_from_studio_default:
|
||||
return
|
||||
|
||||
initialized = True
|
||||
on_change_trigger = []
|
||||
|
||||
self._remove_from_studio_default(on_change_trigger)
|
||||
|
||||
if initialized:
|
||||
for callback in on_change_trigger:
|
||||
callback()
|
||||
|
||||
@abstractmethod
|
||||
def _remove_from_studio_default(self, on_change_trigger):
|
||||
"""Item's implementation to remove studio overrides.
|
||||
|
||||
Mark item as it does not have studio overrides unset studio
|
||||
override values.
|
||||
"""
|
||||
pass
|
||||
|
||||
def add_to_project_override(self, on_change_trigger=None):
|
||||
initialized = False
|
||||
if on_change_trigger is None:
|
||||
if not self.can_add_to_project_override:
|
||||
return
|
||||
|
||||
initialized = True
|
||||
on_change_trigger = []
|
||||
|
||||
self._add_to_project_override(on_change_trigger)
|
||||
|
||||
if initialized:
|
||||
for callback in on_change_trigger:
|
||||
callback()
|
||||
|
||||
@abstractmethod
|
||||
def _add_to_project_override(self, on_change_trigger):
|
||||
"""Item's implementation to set values as overriden for project.
|
||||
|
||||
Mark item and all it's children to be stored as project overrides.
|
||||
"""
|
||||
pass
|
||||
|
||||
def remove_from_project_override(self, on_change_trigger=None):
|
||||
"""Remove project overrides from entity and it's children.
|
||||
|
||||
Reset values to studio overrides or openpype's default and mark entity
|
||||
to not store values as project overrides if entity is not under group.
|
||||
|
||||
This is wrapper method that handles on_change callbacks only when all
|
||||
`_remove_from_project_override` on all children happened. That is
|
||||
important as value changes may trigger change callbacks that must be
|
||||
ignored. Callbacks are triggered by entity where method was called.
|
||||
|
||||
Args:
|
||||
on_change_trigger (list): Callbacks of `on_change` should be stored
|
||||
to trigger them afterwards.
|
||||
"""
|
||||
if self._override_state is not OverrideState.PROJECT:
|
||||
return
|
||||
|
||||
initialized = False
|
||||
if on_change_trigger is None:
|
||||
if not self.can_remove_from_project_override:
|
||||
return
|
||||
initialized = True
|
||||
on_change_trigger = []
|
||||
|
||||
self._remove_from_project_override(on_change_trigger)
|
||||
|
||||
if initialized:
|
||||
for callback in on_change_trigger:
|
||||
callback()
|
||||
|
||||
@abstractmethod
|
||||
def _remove_from_project_override(self, on_change_trigger):
|
||||
"""Item's implementation to remove project overrides.
|
||||
|
||||
Mark item as does not have project overrides. Must not change
|
||||
`was_overriden` attribute value.
|
||||
|
||||
Args:
|
||||
on_change_trigger (list): Callbacks of `on_change` should be stored
|
||||
to trigger them afterwards.
|
||||
"""
|
||||
pass
|
||||
|
||||
def reset_callbacks(self):
|
||||
"""Clear any registered callbacks on entity and all children."""
|
||||
self.on_change_callbacks = []
|
||||
|
||||
|
||||
class ItemEntity(BaseItemEntity):
|
||||
"""Item that is used as hierarchical entity.
|
||||
|
||||
Entity must have defined parent and can't be created outside it's parent.
|
||||
|
||||
Dynamically created entity is entity that can be removed from settings
|
||||
hierarchy and it's key or existence is not defined in schemas. Are
|
||||
created by `ListEntity` or `DictMutableKeysEntity`. Their information about
|
||||
default value or modification is not relevant.
|
||||
|
||||
Args:
|
||||
schema_data (dict): Schema data that defines entity behavior.
|
||||
parent (BaseItemEntity): Parent entity that created this entity.
|
||||
is_dynamic_item (bool): Entity should behave like dynamically created
|
||||
entity.
|
||||
"""
|
||||
_default_label_wrap = {
|
||||
"use_label_wrap": False,
|
||||
"collapsible": True,
|
||||
"collapsed": False
|
||||
}
|
||||
|
||||
def __init__(self, schema_data, parent, is_dynamic_item=False):
|
||||
super(ItemEntity, self).__init__(schema_data)
|
||||
|
||||
self.parent = parent
|
||||
self.is_dynamic_item = is_dynamic_item
|
||||
|
||||
self.is_file = self.schema_data.get("is_file", False)
|
||||
self.is_group = self.schema_data.get("is_group", False)
|
||||
self.is_in_dynamic_item = bool(
|
||||
not self.is_dynamic_item
|
||||
and (self.parent.is_dynamic_item or self.parent.is_in_dynamic_item)
|
||||
)
|
||||
|
||||
# Dynamic item can't have key defined in it-self
|
||||
# - key is defined by it's parent
|
||||
if self.is_dynamic_item:
|
||||
self.require_key = False
|
||||
|
||||
# If value should be stored to environments and uder which group key
|
||||
# - the key may be dynamically changed by it's parent on save
|
||||
self.env_group_key = self.schema_data.get("env_group_key")
|
||||
self.is_env_group = bool(self.env_group_key is not None)
|
||||
|
||||
# Root item reference
|
||||
self.root_item = self.parent.root_item
|
||||
|
||||
# File item reference
|
||||
if self.parent.is_file:
|
||||
self.file_item = self.parent
|
||||
elif self.parent.file_item:
|
||||
self.file_item = self.parent.file_item
|
||||
|
||||
# Group item reference
|
||||
if self.parent.is_group:
|
||||
self.group_item = self.parent
|
||||
elif self.parent.group_item:
|
||||
self.group_item = self.parent.group_item
|
||||
|
||||
self.key = self.schema_data.get("key")
|
||||
self.label = self.schema_data.get("label")
|
||||
|
||||
# GUI attributes
|
||||
_default_label_wrap = self.__class__._default_label_wrap
|
||||
for key, value in ItemEntity._default_label_wrap.items():
|
||||
if key not in _default_label_wrap:
|
||||
self.log.warning(
|
||||
"Class {} miss default label wrap key \"{}\"".format(
|
||||
self.__class__.__name__, key
|
||||
)
|
||||
)
|
||||
_default_label_wrap[key] = value
|
||||
|
||||
use_label_wrap = self.schema_data.get("use_label_wrap")
|
||||
if use_label_wrap is None:
|
||||
if not self.label:
|
||||
use_label_wrap = False
|
||||
else:
|
||||
use_label_wrap = _default_label_wrap["use_label_wrap"]
|
||||
self.use_label_wrap = use_label_wrap
|
||||
|
||||
# Used only if `use_label_wrap` is set to True
|
||||
self.collapsible = self.schema_data.get(
|
||||
"collapsible",
|
||||
_default_label_wrap["collapsible"]
|
||||
)
|
||||
self.collapsed = self.schema_data.get(
|
||||
"collapsed",
|
||||
_default_label_wrap["collapsed"]
|
||||
)
|
||||
|
||||
self._item_initalization()
|
||||
|
||||
def save(self):
|
||||
"""Call save on root item."""
|
||||
self.root_item.save()
|
||||
|
||||
def schema_validations(self):
|
||||
if not self.label and self.use_label_wrap:
|
||||
reason = (
|
||||
"Entity has set `use_label_wrap` to true but"
|
||||
" does not have set `label`."
|
||||
)
|
||||
raise EntitySchemaError(self, reason)
|
||||
|
||||
super(ItemEntity, self).schema_validations()
|
||||
|
||||
def create_schema_object(self, *args, **kwargs):
|
||||
"""Reference method for creation of entities defined in RootEntity."""
|
||||
return self.root_item.create_schema_object(*args, **kwargs)
|
||||
|
||||
def get_entity_from_path(self, path):
|
||||
return self.root_item.get_entity_from_path(path)
|
||||
|
||||
@abstractmethod
|
||||
def update_default_value(self, parent_values):
|
||||
"""Fill default values on startup or on refresh.
|
||||
|
||||
Default values stored in `openpype` repository should update all items
|
||||
in schema. Each item should take values for his key and set it's value
|
||||
or pass values down to children items.
|
||||
|
||||
Args:
|
||||
parent_values (dict): Values of parent's item. But in case item is
|
||||
used as widget, `parent_values` contain value for item.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update_studio_value(self, parent_values):
|
||||
"""Fill studio override values on startup or on refresh.
|
||||
|
||||
Set studio value if is not set to NOT_SET, in that case studio
|
||||
overrides are not set yet.
|
||||
|
||||
Args:
|
||||
parent_values (dict): Values of parent's item. But in case item is
|
||||
used as widget, `parent_values` contain value for item.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update_project_value(self, parent_values):
|
||||
"""Fill project override values on startup, refresh or project change.
|
||||
|
||||
Set project value if is not set to NOT_SET, in that case project
|
||||
overrides are not set yet.
|
||||
|
||||
Args:
|
||||
parent_values (dict): Values of parent's item. But in case item is
|
||||
used as widget, `parent_values` contain value for item.
|
||||
"""
|
||||
pass
|
||||
489
openpype/settings/entities/dict_immutable_keys_entity.py
Normal file
489
openpype/settings/entities/dict_immutable_keys_entity.py
Normal file
|
|
@ -0,0 +1,489 @@
|
|||
import copy
|
||||
|
||||
from .lib import (
|
||||
WRAPPER_TYPES,
|
||||
OverrideState,
|
||||
NOT_SET
|
||||
)
|
||||
from openpype.settings.constants import (
|
||||
METADATA_KEYS,
|
||||
M_OVERRIDEN_KEY,
|
||||
KEY_REGEX
|
||||
)
|
||||
from . import (
|
||||
BaseItemEntity,
|
||||
ItemEntity,
|
||||
BoolEntity,
|
||||
GUIEntity
|
||||
)
|
||||
from .exceptions import (
|
||||
SchemaDuplicatedKeys,
|
||||
EntitySchemaError,
|
||||
InvalidKeySymbols
|
||||
)
|
||||
|
||||
|
||||
class DictImmutableKeysEntity(ItemEntity):
|
||||
"""Entity that represents dictionary with predefined keys.
|
||||
|
||||
Entity's keys can't be removed or added and children type is defined in
|
||||
schema data.
|
||||
|
||||
It is possible to use entity similar way as `dict` object. Returned values
|
||||
are not real settings values but entities representing the value.
|
||||
"""
|
||||
schema_types = ["dict"]
|
||||
_default_label_wrap = {
|
||||
"use_label_wrap": True,
|
||||
"collapsible": True,
|
||||
"collapsed": True
|
||||
}
|
||||
|
||||
def __getitem__(self, key):
|
||||
"""Return entity inder key."""
|
||||
return self.non_gui_children[key]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
"""Set value of item under key."""
|
||||
child_obj = self.non_gui_children[key]
|
||||
child_obj.set(value)
|
||||
|
||||
def __iter__(self):
|
||||
"""Iter through keys."""
|
||||
for key in self.keys():
|
||||
yield key
|
||||
|
||||
def __contains__(self, key):
|
||||
"""Check if key is available."""
|
||||
return key in self.non_gui_children
|
||||
|
||||
def get(self, key, default=None):
|
||||
"""Safe entity getter by key."""
|
||||
return self.non_gui_children.get(key, default)
|
||||
|
||||
def keys(self):
|
||||
"""Entity's keys."""
|
||||
return self.non_gui_children.keys()
|
||||
|
||||
def values(self):
|
||||
"""Children entities."""
|
||||
return self.non_gui_children.values()
|
||||
|
||||
def items(self):
|
||||
"""Children entities paired with their key (key, value)."""
|
||||
return self.non_gui_children.items()
|
||||
|
||||
def set(self, value):
|
||||
"""Set value."""
|
||||
new_value = self.convert_to_valid_type(value)
|
||||
for _key, _value in new_value.items():
|
||||
self.non_gui_children[_key].set(_value)
|
||||
|
||||
def schema_validations(self):
|
||||
"""Validation of schema data."""
|
||||
children_keys = set()
|
||||
for child_entity in self.children:
|
||||
if not isinstance(child_entity, BaseItemEntity):
|
||||
continue
|
||||
elif child_entity.key not in children_keys:
|
||||
children_keys.add(child_entity.key)
|
||||
else:
|
||||
raise SchemaDuplicatedKeys(self, child_entity.key)
|
||||
|
||||
for key in self.keys():
|
||||
if not KEY_REGEX.match(key):
|
||||
raise InvalidKeySymbols(self.path, key)
|
||||
|
||||
if self.checkbox_key:
|
||||
checkbox_child = self.non_gui_children.get(self.checkbox_key)
|
||||
if not checkbox_child:
|
||||
reason = "Checkbox children \"{}\" was not found.".format(
|
||||
self.checkbox_key
|
||||
)
|
||||
raise EntitySchemaError(self, reason)
|
||||
|
||||
if not isinstance(checkbox_child, BoolEntity):
|
||||
reason = (
|
||||
"Checkbox children \"{}\" is not `boolean` type."
|
||||
).format(self.checkbox_key)
|
||||
raise EntitySchemaError(self, reason)
|
||||
|
||||
super(DictImmutableKeysEntity, self).schema_validations()
|
||||
# Trigger schema validation on children entities
|
||||
for child_obj in self.children:
|
||||
child_obj.schema_validations()
|
||||
|
||||
def on_change(self):
|
||||
"""Update metadata on change and pass change to parent."""
|
||||
self._update_current_metadata()
|
||||
|
||||
for callback in self.on_change_callbacks:
|
||||
callback()
|
||||
self.parent.on_child_change(self)
|
||||
|
||||
def on_child_change(self, _child_obj):
|
||||
"""Trigger on change callback if child changes are not ignored."""
|
||||
if not self._ignore_child_changes:
|
||||
self.on_change()
|
||||
|
||||
def _add_children(self, schema_data, first=True):
|
||||
"""Add children from schema data and separate gui wrappers.
|
||||
|
||||
Wrappers are stored in way so tool can create them and keep relation
|
||||
to entities.
|
||||
|
||||
Args:
|
||||
schema_data (dict): Schema data of an entity.
|
||||
first (bool): Helper to know if was method called from inside of
|
||||
method when handling gui wrappers.
|
||||
"""
|
||||
added_children = []
|
||||
for children_schema in schema_data["children"]:
|
||||
if children_schema["type"] in WRAPPER_TYPES:
|
||||
_children_schema = copy.deepcopy(children_schema)
|
||||
wrapper_children = self._add_children(
|
||||
children_schema, False
|
||||
)
|
||||
_children_schema["children"] = wrapper_children
|
||||
added_children.append(_children_schema)
|
||||
continue
|
||||
|
||||
child_obj = self.create_schema_object(children_schema, self)
|
||||
self.children.append(child_obj)
|
||||
added_children.append(child_obj)
|
||||
if isinstance(child_obj, GUIEntity):
|
||||
continue
|
||||
|
||||
self.non_gui_children[child_obj.key] = child_obj
|
||||
|
||||
if not first:
|
||||
return added_children
|
||||
|
||||
for child_obj in added_children:
|
||||
self.gui_layout.append(child_obj)
|
||||
|
||||
def _item_initalization(self):
|
||||
self._default_metadata = NOT_SET
|
||||
self._studio_override_metadata = NOT_SET
|
||||
self._project_override_metadata = NOT_SET
|
||||
|
||||
self._ignore_child_changes = False
|
||||
|
||||
# `current_metadata` are still when schema is loaded
|
||||
# - only metadata stored with dict item are gorup overrides in
|
||||
# M_OVERRIDEN_KEY
|
||||
self._current_metadata = {}
|
||||
self._metadata_are_modified = False
|
||||
|
||||
# Children are stored by key as keys are immutable and are defined by
|
||||
# schema
|
||||
self.valid_value_types = (dict, )
|
||||
self.children = []
|
||||
self.non_gui_children = {}
|
||||
self.gui_layout = []
|
||||
self._add_children(self.schema_data)
|
||||
|
||||
if self.is_dynamic_item:
|
||||
self.require_key = False
|
||||
|
||||
# GUI attributes
|
||||
self.checkbox_key = self.schema_data.get("checkbox_key")
|
||||
self.highlight_content = self.schema_data.get(
|
||||
"highlight_content", False
|
||||
)
|
||||
self.show_borders = self.schema_data.get("show_borders", True)
|
||||
|
||||
def get_child_path(self, child_obj):
|
||||
"""Get hierarchical path of child entity.
|
||||
|
||||
Child must be entity's direct children.
|
||||
"""
|
||||
result_key = None
|
||||
for key, _child_obj in self.non_gui_children.items():
|
||||
if _child_obj is child_obj:
|
||||
result_key = key
|
||||
break
|
||||
|
||||
if result_key is None:
|
||||
raise ValueError("Didn't found child {}".format(child_obj))
|
||||
|
||||
return "/".join([self.path, result_key])
|
||||
|
||||
def _update_current_metadata(self):
|
||||
current_metadata = {}
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
if self._override_state is OverrideState.DEFAULTS:
|
||||
break
|
||||
|
||||
if not child_obj.is_group:
|
||||
continue
|
||||
|
||||
if (
|
||||
self._override_state is OverrideState.STUDIO
|
||||
and not child_obj.has_studio_override
|
||||
):
|
||||
continue
|
||||
|
||||
if (
|
||||
self._override_state is OverrideState.PROJECT
|
||||
and not child_obj.has_project_override
|
||||
):
|
||||
continue
|
||||
|
||||
if M_OVERRIDEN_KEY not in current_metadata:
|
||||
current_metadata[M_OVERRIDEN_KEY] = []
|
||||
current_metadata[M_OVERRIDEN_KEY].append(key)
|
||||
|
||||
# Define if current metadata are avaialble for current override state
|
||||
metadata = NOT_SET
|
||||
if self._override_state is OverrideState.STUDIO:
|
||||
metadata = self._studio_override_metadata
|
||||
|
||||
elif self._override_state is OverrideState.PROJECT:
|
||||
metadata = self._project_override_metadata
|
||||
|
||||
if metadata is NOT_SET:
|
||||
metadata = {}
|
||||
|
||||
self._metadata_are_modified = current_metadata != metadata
|
||||
self._current_metadata = current_metadata
|
||||
|
||||
def set_override_state(self, state):
|
||||
# Trigger override state change of root if is not same
|
||||
if self.root_item.override_state is not state:
|
||||
self.root_item.set_override_state(state)
|
||||
return
|
||||
|
||||
# Change has/had override states
|
||||
self._override_state = state
|
||||
|
||||
for child_obj in self.non_gui_children.values():
|
||||
child_obj.set_override_state(state)
|
||||
|
||||
self._update_current_metadata()
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
output = {}
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
output[key] = child_obj.value
|
||||
return output
|
||||
|
||||
@property
|
||||
def has_unsaved_changes(self):
|
||||
if self._metadata_are_modified:
|
||||
return True
|
||||
|
||||
return self._child_has_unsaved_changes
|
||||
|
||||
@property
|
||||
def _child_has_unsaved_changes(self):
|
||||
for child_obj in self.non_gui_children.values():
|
||||
if child_obj.has_unsaved_changes:
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def has_studio_override(self):
|
||||
return self._child_has_studio_override
|
||||
|
||||
@property
|
||||
def _child_has_studio_override(self):
|
||||
if self._override_state >= OverrideState.STUDIO:
|
||||
for child_obj in self.non_gui_children.values():
|
||||
if child_obj.has_studio_override:
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def has_project_override(self):
|
||||
return self._child_has_project_override
|
||||
|
||||
@property
|
||||
def _child_has_project_override(self):
|
||||
if self._override_state >= OverrideState.PROJECT:
|
||||
for child_obj in self.non_gui_children.values():
|
||||
if child_obj.has_project_override:
|
||||
return True
|
||||
return False
|
||||
|
||||
def settings_value(self):
|
||||
if self._override_state is OverrideState.NOT_DEFINED:
|
||||
return NOT_SET
|
||||
|
||||
if self._override_state is OverrideState.DEFAULTS:
|
||||
output = {}
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
child_value = child_obj.settings_value()
|
||||
if not child_obj.is_file and not child_obj.file_item:
|
||||
for _key, _value in child_value.items():
|
||||
new_key = "/".join([key, _key])
|
||||
output[new_key] = _value
|
||||
else:
|
||||
output[key] = child_value
|
||||
return output
|
||||
|
||||
if self.is_group:
|
||||
if self._override_state is OverrideState.STUDIO:
|
||||
if not self.has_studio_override:
|
||||
return NOT_SET
|
||||
elif self._override_state is OverrideState.PROJECT:
|
||||
if not self.has_project_override:
|
||||
return NOT_SET
|
||||
|
||||
output = {}
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
value = child_obj.settings_value()
|
||||
if value is not NOT_SET:
|
||||
output[key] = value
|
||||
|
||||
if not output:
|
||||
return NOT_SET
|
||||
|
||||
output.update(self._current_metadata)
|
||||
return output
|
||||
|
||||
def _prepare_value(self, value):
|
||||
if value is NOT_SET:
|
||||
return NOT_SET, NOT_SET
|
||||
|
||||
# Create copy of value before poping values
|
||||
value = copy.deepcopy(value)
|
||||
metadata = {}
|
||||
for key in METADATA_KEYS:
|
||||
if key in value:
|
||||
metadata[key] = value.pop(key)
|
||||
return value, metadata
|
||||
|
||||
def update_default_value(self, value):
|
||||
"""Update default values.
|
||||
|
||||
Not an api method, should be called by parent.
|
||||
"""
|
||||
value = self._check_update_value(value, "default")
|
||||
self.has_default_value = value is not NOT_SET
|
||||
# TODO add value validation
|
||||
value, metadata = self._prepare_value(value)
|
||||
self._default_metadata = metadata
|
||||
|
||||
if value is NOT_SET:
|
||||
for child_obj in self.non_gui_children.values():
|
||||
child_obj.update_default_value(value)
|
||||
return
|
||||
|
||||
value_keys = set(value.keys())
|
||||
expected_keys = set(self.non_gui_children)
|
||||
unknown_keys = value_keys - expected_keys
|
||||
if unknown_keys:
|
||||
self.log.warning(
|
||||
"{} Unknown keys in default values: {}".format(
|
||||
self.path,
|
||||
", ".join("\"{}\"".format(key) for key in unknown_keys)
|
||||
)
|
||||
)
|
||||
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
child_value = value.get(key, NOT_SET)
|
||||
child_obj.update_default_value(child_value)
|
||||
|
||||
def update_studio_value(self, value):
|
||||
"""Update studio override values.
|
||||
|
||||
Not an api method, should be called by parent.
|
||||
"""
|
||||
value = self._check_update_value(value, "studio override")
|
||||
value, metadata = self._prepare_value(value)
|
||||
self._studio_override_metadata = metadata
|
||||
self.had_studio_override = metadata is not NOT_SET
|
||||
|
||||
if value is NOT_SET:
|
||||
for child_obj in self.non_gui_children.values():
|
||||
child_obj.update_studio_value(value)
|
||||
return
|
||||
|
||||
value_keys = set(value.keys())
|
||||
expected_keys = set(self.non_gui_children)
|
||||
unknown_keys = value_keys - expected_keys
|
||||
if unknown_keys:
|
||||
self.log.warning(
|
||||
"{} Unknown keys in studio overrides: {}".format(
|
||||
self.path,
|
||||
", ".join("\"{}\"".format(key) for key in unknown_keys)
|
||||
)
|
||||
)
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
child_value = value.get(key, NOT_SET)
|
||||
child_obj.update_studio_value(child_value)
|
||||
|
||||
def update_project_value(self, value):
|
||||
"""Update project override values.
|
||||
|
||||
Not an api method, should be called by parent.
|
||||
"""
|
||||
value = self._check_update_value(value, "project override")
|
||||
value, metadata = self._prepare_value(value)
|
||||
self._project_override_metadata = metadata
|
||||
self.had_project_override = metadata is not NOT_SET
|
||||
|
||||
if value is NOT_SET:
|
||||
for child_obj in self.non_gui_children.values():
|
||||
child_obj.update_project_value(value)
|
||||
return
|
||||
|
||||
value_keys = set(value.keys())
|
||||
expected_keys = set(self.non_gui_children)
|
||||
unknown_keys = value_keys - expected_keys
|
||||
if unknown_keys:
|
||||
self.log.warning(
|
||||
"{} Unknown keys in project overrides: {}".format(
|
||||
self.path,
|
||||
", ".join("\"{}\"".format(key) for key in unknown_keys)
|
||||
)
|
||||
)
|
||||
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
child_value = value.get(key, NOT_SET)
|
||||
child_obj.update_project_value(child_value)
|
||||
|
||||
def _discard_changes(self, on_change_trigger):
|
||||
self._ignore_child_changes = True
|
||||
|
||||
for child_obj in self.non_gui_children.values():
|
||||
child_obj.discard_changes(on_change_trigger)
|
||||
|
||||
self._ignore_child_changes = False
|
||||
|
||||
def _add_to_studio_default(self, on_change_trigger):
|
||||
self._ignore_child_changes = True
|
||||
for child_obj in self.non_gui_children.values():
|
||||
child_obj.add_to_studio_default(on_change_trigger)
|
||||
self._ignore_child_changes = False
|
||||
self.parent.on_child_change(self)
|
||||
|
||||
def _remove_from_studio_default(self, on_change_trigger):
|
||||
self._ignore_child_changes = True
|
||||
for child_obj in self.non_gui_children.values():
|
||||
child_obj.remove_from_studio_default(on_change_trigger)
|
||||
self._ignore_child_changes = False
|
||||
|
||||
def _add_to_project_override(self, _on_change_trigger):
|
||||
self._ignore_child_changes = True
|
||||
for child_obj in self.non_gui_children.values():
|
||||
child_obj.add_to_project_override(_on_change_trigger)
|
||||
self._ignore_child_changes = False
|
||||
self.parent.on_child_change(self)
|
||||
|
||||
def _remove_from_project_override(self, on_change_trigger):
|
||||
if self._override_state is not OverrideState.PROJECT:
|
||||
return
|
||||
|
||||
self._ignore_child_changes = True
|
||||
for child_obj in self.non_gui_children.values():
|
||||
child_obj.remove_from_project_override(on_change_trigger)
|
||||
self._ignore_child_changes = False
|
||||
|
||||
def reset_callbacks(self):
|
||||
"""Reset registered callbacks on entity and children."""
|
||||
super(DictImmutableKeysEntity, self).reset_callbacks()
|
||||
for child_entity in self.children:
|
||||
child_entity.reset_callbacks()
|
||||
587
openpype/settings/entities/dict_mutable_keys_entity.py
Normal file
587
openpype/settings/entities/dict_mutable_keys_entity.py
Normal file
|
|
@ -0,0 +1,587 @@
|
|||
import re
|
||||
import copy
|
||||
|
||||
from .lib import (
|
||||
NOT_SET,
|
||||
OverrideState
|
||||
)
|
||||
from . import EndpointEntity
|
||||
from .exceptions import (
|
||||
DefaultsNotDefined,
|
||||
InvalidKeySymbols,
|
||||
StudioDefaultsNotDefined,
|
||||
RequiredKeyModified,
|
||||
EntitySchemaError
|
||||
)
|
||||
from openpype.settings.constants import (
|
||||
METADATA_KEYS,
|
||||
M_DYNAMIC_KEY_LABEL,
|
||||
M_ENVIRONMENT_KEY,
|
||||
KEY_REGEX,
|
||||
KEY_ALLOWED_SYMBOLS
|
||||
)
|
||||
|
||||
|
||||
class DictMutableKeysEntity(EndpointEntity):
|
||||
"""Dictionary entity that has mutable keys.
|
||||
|
||||
Keys of entity's children can be modified, removed or added. Children have
|
||||
defined entity type so it is not possible to have 2 different entity types
|
||||
as children.
|
||||
|
||||
TODOs:
|
||||
- cleanup children on pop
|
||||
- remove child's reference to parent
|
||||
- clear callbacks
|
||||
"""
|
||||
schema_types = ["dict-modifiable"]
|
||||
_default_label_wrap = {
|
||||
"use_label_wrap": True,
|
||||
"collapsible": True,
|
||||
"collapsed": True
|
||||
}
|
||||
|
||||
_miss_arg = object()
|
||||
|
||||
def __getitem__(self, key):
|
||||
if key not in self.children_by_key:
|
||||
self.add_key(key)
|
||||
return self.children_by_key[key]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self.set_key_value(key, value)
|
||||
|
||||
def __iter__(self):
|
||||
for key in self.keys():
|
||||
yield key
|
||||
|
||||
def __contains__(self, key):
|
||||
return key in self.children_by_key
|
||||
|
||||
def pop(self, key, *args, **kwargs):
|
||||
if key in self.required_keys:
|
||||
raise RequiredKeyModified(self.path, key)
|
||||
result = self.children_by_key.pop(key, *args, **kwargs)
|
||||
self.on_change()
|
||||
return result
|
||||
|
||||
def get(self, key, default=None):
|
||||
return self.children_by_key.get(key, default)
|
||||
|
||||
def keys(self):
|
||||
return self.children_by_key.keys()
|
||||
|
||||
def values(self):
|
||||
return self.children_by_key.values()
|
||||
|
||||
def items(self):
|
||||
return self.children_by_key.items()
|
||||
|
||||
def clear(self):
|
||||
for key in tuple(self.children_by_key.keys()):
|
||||
self.pop(key)
|
||||
|
||||
def set(self, value):
|
||||
new_value = self.convert_to_valid_type(value)
|
||||
|
||||
prev_keys = set(self.keys())
|
||||
|
||||
for _key, _value in new_value.items():
|
||||
self.set_key_value(_key, _value)
|
||||
if _key in prev_keys:
|
||||
prev_keys.remove(_key)
|
||||
|
||||
for key in prev_keys:
|
||||
self.pop(key)
|
||||
|
||||
def set_key_value(self, key, value):
|
||||
# TODO Check for value type if is Settings entity?
|
||||
child_obj = self.children_by_key.get(key)
|
||||
if not child_obj:
|
||||
if not KEY_REGEX.match(key):
|
||||
raise InvalidKeySymbols(self.path, key)
|
||||
|
||||
child_obj = self.add_key(key)
|
||||
|
||||
child_obj.set(value)
|
||||
|
||||
def change_key(self, old_key, new_key):
|
||||
if old_key in self.required_keys:
|
||||
raise RequiredKeyModified(self.path, old_key)
|
||||
|
||||
if new_key == old_key:
|
||||
return
|
||||
|
||||
if not KEY_REGEX.match(new_key):
|
||||
raise InvalidKeySymbols(self.path, new_key)
|
||||
|
||||
self.children_by_key[new_key] = self.children_by_key.pop(old_key)
|
||||
self._on_key_label_change()
|
||||
|
||||
def _on_key_label_change(self):
|
||||
if self._override_state is OverrideState.STUDIO:
|
||||
self._has_studio_override = True
|
||||
elif self._override_state is OverrideState.PROJECT:
|
||||
self._has_project_override = True
|
||||
self.on_change()
|
||||
|
||||
def _add_key(self, key):
|
||||
if key in self.children_by_key:
|
||||
self.pop(key)
|
||||
|
||||
if not KEY_REGEX.match(key):
|
||||
raise InvalidKeySymbols(self.path, key)
|
||||
|
||||
if self.value_is_env_group:
|
||||
item_schema = copy.deepcopy(self.item_schema)
|
||||
item_schema["env_group_key"] = key
|
||||
else:
|
||||
item_schema = self.item_schema
|
||||
|
||||
new_child = self.create_schema_object(item_schema, self, True)
|
||||
self.children_by_key[key] = new_child
|
||||
return new_child
|
||||
|
||||
def add_key(self, key):
|
||||
new_child = self._add_key(key)
|
||||
new_child.set_override_state(self._override_state)
|
||||
self.on_change()
|
||||
return new_child
|
||||
|
||||
def change_child_key(self, child_entity, new_key):
|
||||
old_key = None
|
||||
for key, child in self.children_by_key.items():
|
||||
if child is child_entity:
|
||||
old_key = key
|
||||
break
|
||||
|
||||
self.change_key(old_key, new_key)
|
||||
|
||||
def get_child_key(self, child_entity):
|
||||
for key, child in self.children_by_key.items():
|
||||
if child is child_entity:
|
||||
return key
|
||||
return None
|
||||
|
||||
# Label methods
|
||||
def get_child_label(self, child_entity):
|
||||
return self.children_label_by_id.get(child_entity.id)
|
||||
|
||||
def set_child_label(self, child_entity, label):
|
||||
self.children_label_by_id[child_entity.id] = label
|
||||
self._on_key_label_change()
|
||||
|
||||
def get_key_label(self, key):
|
||||
child_entity = self.children_by_key[key]
|
||||
return self.get_child_label(child_entity)
|
||||
|
||||
def set_key_label(self, key, label):
|
||||
child_entity = self.children_by_key[key]
|
||||
self.set_child_label(child_entity, label)
|
||||
|
||||
def _item_initalization(self):
|
||||
self._default_metadata = {}
|
||||
self._studio_override_metadata = {}
|
||||
self._project_override_metadata = {}
|
||||
|
||||
self.initial_value = None
|
||||
|
||||
self._ignore_child_changes = False
|
||||
|
||||
self.valid_value_types = (dict, )
|
||||
self.value_on_not_set = {}
|
||||
|
||||
self.children_by_key = {}
|
||||
self.children_label_by_id = {}
|
||||
|
||||
self.value_is_env_group = (
|
||||
self.schema_data.get("value_is_env_group") or False
|
||||
)
|
||||
self.required_keys = self.schema_data.get("required_keys") or []
|
||||
self.collapsible_key = self.schema_data.get("collapsible_key") or False
|
||||
# GUI attributes
|
||||
self.hightlight_content = (
|
||||
self.schema_data.get("highlight_content") or False
|
||||
)
|
||||
|
||||
object_type = self.schema_data.get("object_type") or {}
|
||||
if not isinstance(object_type, dict):
|
||||
# Backwards compatibility
|
||||
object_type = {
|
||||
"type": object_type
|
||||
}
|
||||
input_modifiers = self.schema_data.get("input_modifiers") or {}
|
||||
if input_modifiers:
|
||||
self.log.warning((
|
||||
"Used deprecated key `input_modifiers` to define item."
|
||||
" Rather use `object_type` as dictionary with modifiers."
|
||||
))
|
||||
object_type.update(input_modifiers)
|
||||
self.item_schema = object_type
|
||||
|
||||
if self.value_is_env_group:
|
||||
self.item_schema["env_group_key"] = ""
|
||||
|
||||
if not self.group_item:
|
||||
self.is_group = True
|
||||
|
||||
def schema_validations(self):
|
||||
super(DictMutableKeysEntity, self).schema_validations()
|
||||
|
||||
if not self.schema_data.get("object_type"):
|
||||
reason = (
|
||||
"Modifiable dictionary must have specified `object_type`."
|
||||
)
|
||||
raise EntitySchemaError(self, reason)
|
||||
|
||||
# TODO Ability to store labels should be defined with different key
|
||||
if self.collapsible_key and not self.file_item:
|
||||
reason = (
|
||||
"Modifiable dictionary with collapsible keys is not under"
|
||||
" file item so can't store metadata."
|
||||
)
|
||||
raise EntitySchemaError(self, reason)
|
||||
|
||||
for child_obj in self.children_by_key.values():
|
||||
child_obj.schema_validations()
|
||||
|
||||
def get_child_path(self, child_obj):
|
||||
result_key = None
|
||||
for key, _child_obj in self.children_by_key.items():
|
||||
if _child_obj is child_obj:
|
||||
result_key = key
|
||||
break
|
||||
|
||||
if result_key is None:
|
||||
raise ValueError("Didn't found child {}".format(child_obj))
|
||||
|
||||
return "/".join([self.path, result_key])
|
||||
|
||||
def on_child_change(self, _child_entity):
|
||||
if self._ignore_child_changes:
|
||||
return
|
||||
|
||||
if self._override_state is OverrideState.STUDIO:
|
||||
self._has_studio_override = True
|
||||
elif self._override_state is OverrideState.PROJECT:
|
||||
self._has_project_override = True
|
||||
|
||||
self.on_change()
|
||||
|
||||
def _metadata_for_current_state(self):
|
||||
if (
|
||||
self._override_state is OverrideState.PROJECT
|
||||
and self._project_override_value is not NOT_SET
|
||||
):
|
||||
return self._project_override_metadata
|
||||
|
||||
if (
|
||||
self._override_state >= OverrideState.STUDIO
|
||||
and self._studio_override_value is not NOT_SET
|
||||
):
|
||||
return self._studio_override_metadata
|
||||
|
||||
return self._default_metadata
|
||||
|
||||
def set_override_state(self, state):
|
||||
# Trigger override state change of root if is not same
|
||||
if self.root_item.override_state is not state:
|
||||
self.root_item.set_override_state(state)
|
||||
return
|
||||
|
||||
# TODO change metadata
|
||||
self._override_state = state
|
||||
# Ignore if is dynamic item and use default in that case
|
||||
if not self.is_dynamic_item and not self.is_in_dynamic_item:
|
||||
if state > OverrideState.DEFAULTS:
|
||||
if not self.has_default_value:
|
||||
raise DefaultsNotDefined(self)
|
||||
|
||||
elif state > OverrideState.STUDIO:
|
||||
if not self.had_studio_override:
|
||||
raise StudioDefaultsNotDefined(self)
|
||||
|
||||
if state is OverrideState.STUDIO:
|
||||
self._has_studio_override = self.had_studio_override
|
||||
|
||||
elif state is OverrideState.PROJECT:
|
||||
self._has_project_override = self.had_project_override
|
||||
self._has_studio_override = self.had_studio_override
|
||||
|
||||
using_project_overrides = False
|
||||
using_studio_overrides = False
|
||||
if (
|
||||
state is OverrideState.PROJECT
|
||||
and self.had_project_override
|
||||
):
|
||||
using_project_overrides = True
|
||||
value = self._project_override_value
|
||||
metadata = self._project_override_metadata
|
||||
|
||||
elif (
|
||||
state >= OverrideState.STUDIO
|
||||
and self.had_studio_override
|
||||
):
|
||||
using_studio_overrides = True
|
||||
value = self._studio_override_value
|
||||
metadata = self._studio_override_metadata
|
||||
|
||||
else:
|
||||
value = self._default_value
|
||||
metadata = self._default_metadata
|
||||
|
||||
if value is NOT_SET:
|
||||
value = self.value_on_not_set
|
||||
|
||||
new_value = copy.deepcopy(value)
|
||||
|
||||
# Simulate `clear` method without triggering value change
|
||||
for key in tuple(self.children_by_key.keys()):
|
||||
self.children_by_key.pop(key)
|
||||
|
||||
for required_key in self.required_keys:
|
||||
if required_key not in new_value:
|
||||
new_value[required_key] = NOT_SET
|
||||
|
||||
# Create new children
|
||||
children_label_by_id = {}
|
||||
metadata_labels = metadata.get(M_DYNAMIC_KEY_LABEL) or {}
|
||||
for _key, _value in new_value.items():
|
||||
if not KEY_REGEX.match(_key):
|
||||
# Replace invalid characters with underscore
|
||||
# - this is safety to not break already existing settings
|
||||
_key = re.sub(
|
||||
r"[^{}]+".format(KEY_ALLOWED_SYMBOLS),
|
||||
"_",
|
||||
_key
|
||||
)
|
||||
|
||||
child_entity = self._add_key(_key)
|
||||
child_entity.update_default_value(_value)
|
||||
if using_project_overrides:
|
||||
child_entity.update_project_value(_value)
|
||||
elif using_studio_overrides:
|
||||
child_entity.update_studio_value(_value)
|
||||
|
||||
label = metadata_labels.get(_key)
|
||||
if label:
|
||||
children_label_by_id[child_entity.id] = label
|
||||
child_entity.set_override_state(state)
|
||||
|
||||
self.children_label_by_id = children_label_by_id
|
||||
|
||||
self.initial_value = self.settings_value()
|
||||
|
||||
def children_key_by_id(self):
|
||||
return {
|
||||
child_entity.id: key
|
||||
for key, child_entity in self.children_by_key.items()
|
||||
}
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
output = {}
|
||||
for key, child_entity in self.children_by_key.items():
|
||||
output[key] = child_entity.value
|
||||
return output
|
||||
|
||||
@property
|
||||
def metadata(self):
|
||||
output = {}
|
||||
if not self.children_label_by_id:
|
||||
return output
|
||||
|
||||
children_key_by_id = self.children_key_by_id()
|
||||
label_metadata = {}
|
||||
for child_id, label in self.children_label_by_id.items():
|
||||
key = children_key_by_id.get(child_id)
|
||||
if key:
|
||||
label_metadata[key] = label
|
||||
|
||||
output[M_DYNAMIC_KEY_LABEL] = label_metadata
|
||||
|
||||
return output
|
||||
|
||||
@property
|
||||
def has_unsaved_changes(self):
|
||||
if (
|
||||
self._override_state is OverrideState.PROJECT
|
||||
and self._has_project_override != self.had_project_override
|
||||
):
|
||||
return True
|
||||
|
||||
elif (
|
||||
self._override_state is OverrideState.STUDIO
|
||||
and self._has_studio_override != self.had_studio_override
|
||||
):
|
||||
return True
|
||||
|
||||
if self._child_has_unsaved_changes:
|
||||
return True
|
||||
|
||||
if self.metadata != self._metadata_for_current_state():
|
||||
return True
|
||||
|
||||
if self.settings_value() != self.initial_value:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@property
|
||||
def _child_has_unsaved_changes(self):
|
||||
for child_obj in self.children_by_key.values():
|
||||
if child_obj.has_unsaved_changes:
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def has_studio_override(self):
|
||||
return self._has_studio_override or self._child_has_studio_override
|
||||
|
||||
@property
|
||||
def _child_has_studio_override(self):
|
||||
if self._override_state >= OverrideState.STUDIO:
|
||||
for child_obj in self.children_by_key.values():
|
||||
if child_obj.has_studio_override:
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def has_project_override(self):
|
||||
return self._has_project_override or self._child_has_project_override
|
||||
|
||||
@property
|
||||
def _child_has_project_override(self):
|
||||
if self._override_state >= OverrideState.PROJECT:
|
||||
for child_obj in self.children_by_key.values():
|
||||
if child_obj.has_project_override:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _settings_value(self):
|
||||
output = {}
|
||||
for key, child_entity in self.children_by_key.items():
|
||||
child_value = child_entity.settings_value()
|
||||
# TODO child should have setter of env group key se child can
|
||||
# know what env group represents.
|
||||
if self.value_is_env_group:
|
||||
if key not in child_value[M_ENVIRONMENT_KEY]:
|
||||
_metadata = child_value[M_ENVIRONMENT_KEY]
|
||||
_m_keykey = tuple(_metadata.keys())[0]
|
||||
env_keys = child_value[M_ENVIRONMENT_KEY].pop(_m_keykey)
|
||||
child_value[M_ENVIRONMENT_KEY][key] = env_keys
|
||||
output[key] = child_value
|
||||
output.update(self.metadata)
|
||||
return output
|
||||
|
||||
def _prepare_value(self, value):
|
||||
metadata = {}
|
||||
if isinstance(value, dict):
|
||||
for key in METADATA_KEYS:
|
||||
if key in value:
|
||||
metadata[key] = value.pop(key)
|
||||
return value, metadata
|
||||
|
||||
def update_default_value(self, value):
|
||||
value = self._check_update_value(value, "default")
|
||||
has_default_value = value is not NOT_SET
|
||||
if has_default_value:
|
||||
for required_key in self.required_keys:
|
||||
if required_key not in value:
|
||||
has_default_value = False
|
||||
break
|
||||
self.has_default_value = has_default_value
|
||||
value, metadata = self._prepare_value(value)
|
||||
self._default_value = value
|
||||
self._default_metadata = metadata
|
||||
|
||||
def update_studio_value(self, value):
|
||||
value = self._check_update_value(value, "studio override")
|
||||
value, metadata = self._prepare_value(value)
|
||||
self._studio_override_value = value
|
||||
self._studio_override_metadata = metadata
|
||||
self.had_studio_override = value is not NOT_SET
|
||||
|
||||
def update_project_value(self, value):
|
||||
value = self._check_update_value(value, "project override")
|
||||
value, metadata = self._prepare_value(value)
|
||||
self._project_override_value = value
|
||||
self._project_override_metadata = metadata
|
||||
self.had_project_override = value is not NOT_SET
|
||||
|
||||
def _discard_changes(self, on_change_trigger):
|
||||
self.set_override_state(self._override_state)
|
||||
on_change_trigger.append(self.on_change)
|
||||
|
||||
def _add_to_studio_default(self, _on_change_trigger):
|
||||
self._has_studio_override = True
|
||||
self.on_change()
|
||||
|
||||
def _remove_from_studio_default(self, on_change_trigger):
|
||||
value = self._default_value
|
||||
if value is NOT_SET:
|
||||
value = self.value_on_not_set
|
||||
|
||||
new_value = copy.deepcopy(value)
|
||||
self._ignore_child_changes = True
|
||||
|
||||
# Simulate `clear` method without triggering value change
|
||||
for key in tuple(self.children_by_key.keys()):
|
||||
child_obj = self.children_by_key.pop(key)
|
||||
|
||||
# Create new children
|
||||
for _key, _value in new_value.items():
|
||||
child_obj = self._add_key(_key)
|
||||
child_obj.update_default_value(_value)
|
||||
child_obj.set_override_state(self._override_state)
|
||||
|
||||
self._ignore_child_changes = False
|
||||
|
||||
self._has_studio_override = False
|
||||
|
||||
on_change_trigger.append(self.on_change)
|
||||
|
||||
def _add_to_project_override(self, _on_change_trigger):
|
||||
self._has_project_override = True
|
||||
self.on_change()
|
||||
|
||||
def _remove_from_project_override(self, on_change_trigger):
|
||||
if self._override_state is not OverrideState.PROJECT:
|
||||
return
|
||||
|
||||
if not self.has_project_override:
|
||||
return
|
||||
|
||||
if self._has_studio_override:
|
||||
value = self._studio_override_value
|
||||
elif self.has_default_value:
|
||||
value = self._default_value
|
||||
else:
|
||||
value = self.value_on_not_set
|
||||
|
||||
new_value = copy.deepcopy(value)
|
||||
|
||||
self._ignore_child_changes = True
|
||||
|
||||
# Simulate `clear` method without triggering value change
|
||||
for key in tuple(self.children_by_key.keys()):
|
||||
child_obj = self.children_by_key.pop(key)
|
||||
|
||||
# Create new children
|
||||
for _key, _value in new_value.items():
|
||||
child_obj = self._add_key(_key)
|
||||
child_obj.update_default_value(_value)
|
||||
if self._has_studio_override:
|
||||
child_obj.update_studio_value(_value)
|
||||
child_obj.set_override_state(self._override_state)
|
||||
|
||||
self._ignore_child_changes = False
|
||||
|
||||
self._has_project_override = False
|
||||
|
||||
on_change_trigger.append(self.on_change)
|
||||
|
||||
def reset_callbacks(self):
|
||||
super(DictMutableKeysEntity, self).reset_callbacks()
|
||||
for child_entity in self.children_by_key.values():
|
||||
child_entity.reset_callbacks()
|
||||
211
openpype/settings/entities/enum_entity.py
Normal file
211
openpype/settings/entities/enum_entity.py
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
from .input_entities import InputEntity
|
||||
from .exceptions import EntitySchemaError
|
||||
from .lib import (
|
||||
NOT_SET,
|
||||
STRING_TYPE
|
||||
)
|
||||
|
||||
|
||||
class BaseEnumEntity(InputEntity):
|
||||
def _item_initalization(self):
|
||||
self.multiselection = True
|
||||
self.value_on_not_set = None
|
||||
self.enum_items = None
|
||||
self.valid_keys = None
|
||||
self.valid_value_types = None
|
||||
self.placeholder = None
|
||||
|
||||
def schema_validations(self):
|
||||
if not isinstance(self.enum_items, list):
|
||||
raise EntitySchemaError(
|
||||
self, "Enum item must have defined `enum_items` as list."
|
||||
)
|
||||
|
||||
enum_keys = set()
|
||||
for item in self.enum_items:
|
||||
key = tuple(item.keys())[0]
|
||||
if key in enum_keys:
|
||||
reason = "Key \"{}\" is more than once in enum items.".format(
|
||||
key
|
||||
)
|
||||
raise EntitySchemaError(self, reason)
|
||||
|
||||
enum_keys.add(key)
|
||||
|
||||
if not isinstance(key, STRING_TYPE):
|
||||
reason = "Key \"{}\" has invalid type {}, expected {}.".format(
|
||||
key, type(key), STRING_TYPE
|
||||
)
|
||||
raise EntitySchemaError(self, reason)
|
||||
|
||||
super(BaseEnumEntity, self).schema_validations()
|
||||
|
||||
def _convert_to_valid_type(self, value):
|
||||
if self.multiselection:
|
||||
if isinstance(value, (set, tuple)):
|
||||
return list(value)
|
||||
elif isinstance(value, (int, float)):
|
||||
return str(value)
|
||||
return NOT_SET
|
||||
|
||||
def set(self, value):
|
||||
new_value = self.convert_to_valid_type(value)
|
||||
if self.multiselection:
|
||||
check_values = new_value
|
||||
else:
|
||||
check_values = [new_value]
|
||||
|
||||
for item in check_values:
|
||||
if item not in self.valid_keys:
|
||||
raise ValueError(
|
||||
"{} Invalid value \"{}\". Expected one of: {}".format(
|
||||
self.path, item, self.valid_keys
|
||||
)
|
||||
)
|
||||
self._current_value = new_value
|
||||
self._on_value_change()
|
||||
|
||||
|
||||
class EnumEntity(BaseEnumEntity):
|
||||
schema_types = ["enum"]
|
||||
|
||||
def _item_initalization(self):
|
||||
self.multiselection = self.schema_data.get("multiselection", False)
|
||||
self.enum_items = self.schema_data.get("enum_items")
|
||||
|
||||
valid_keys = set()
|
||||
for item in self.enum_items or []:
|
||||
valid_keys.add(tuple(item.keys())[0])
|
||||
|
||||
self.valid_keys = valid_keys
|
||||
|
||||
if self.multiselection:
|
||||
self.valid_value_types = (list, )
|
||||
self.value_on_not_set = []
|
||||
else:
|
||||
for key in valid_keys:
|
||||
if self.value_on_not_set is NOT_SET:
|
||||
self.value_on_not_set = key
|
||||
break
|
||||
|
||||
self.valid_value_types = (STRING_TYPE, )
|
||||
|
||||
# GUI attribute
|
||||
self.placeholder = self.schema_data.get("placeholder")
|
||||
|
||||
def schema_validations(self):
|
||||
if not self.enum_items and "enum_items" not in self.schema_data:
|
||||
raise EntitySchemaError(
|
||||
self, "Enum item must have defined `enum_items`"
|
||||
)
|
||||
super(EnumEntity, self).schema_validations()
|
||||
|
||||
|
||||
class AppsEnumEntity(BaseEnumEntity):
|
||||
schema_types = ["apps-enum"]
|
||||
|
||||
def _item_initalization(self):
|
||||
self.multiselection = True
|
||||
self.value_on_not_set = []
|
||||
self.enum_items = []
|
||||
self.valid_keys = set()
|
||||
self.valid_value_types = (list, )
|
||||
self.placeholder = None
|
||||
|
||||
def _get_enum_values(self):
|
||||
system_settings_entity = self.get_entity_from_path("system_settings")
|
||||
|
||||
valid_keys = set()
|
||||
enum_items = []
|
||||
applications_entity = system_settings_entity["applications"]
|
||||
for group_name, app_group in applications_entity.items():
|
||||
enabled_entity = app_group.get("enabled")
|
||||
if enabled_entity and not enabled_entity.value:
|
||||
continue
|
||||
|
||||
host_name_entity = app_group.get("host_name")
|
||||
if not host_name_entity or not host_name_entity.value:
|
||||
continue
|
||||
|
||||
group_label = app_group["label"].value
|
||||
|
||||
for variant_name, variant_entity in app_group["variants"].items():
|
||||
enabled_entity = variant_entity.get("enabled")
|
||||
if enabled_entity and not enabled_entity.value:
|
||||
continue
|
||||
|
||||
variant_label = variant_entity["variant_label"].value
|
||||
if group_label:
|
||||
full_label = "{} {}".format(group_label, variant_label)
|
||||
else:
|
||||
full_label = variant_label
|
||||
|
||||
full_name = "/".join((group_name, variant_name))
|
||||
enum_items.append({full_name: full_label})
|
||||
valid_keys.add(full_name)
|
||||
return enum_items, valid_keys
|
||||
|
||||
def set_override_state(self, *args, **kwargs):
|
||||
super(AppsEnumEntity, self).set_override_state(*args, **kwargs)
|
||||
|
||||
self.enum_items, self.valid_keys = self._get_enum_values()
|
||||
new_value = []
|
||||
for key in self._current_value:
|
||||
if key in self.valid_keys:
|
||||
new_value.append(key)
|
||||
self._current_value = new_value
|
||||
|
||||
|
||||
class ToolsEnumEntity(BaseEnumEntity):
|
||||
schema_types = ["tools-enum"]
|
||||
|
||||
def _item_initalization(self):
|
||||
self.multiselection = True
|
||||
self.value_on_not_set = []
|
||||
self.enum_items = []
|
||||
self.valid_keys = set()
|
||||
self.valid_value_types = (list, )
|
||||
self.placeholder = None
|
||||
|
||||
def _get_enum_values(self):
|
||||
system_settings_entity = self.get_entity_from_path("system_settings")
|
||||
|
||||
valid_keys = set()
|
||||
enum_items = []
|
||||
tool_groups_entity = system_settings_entity["tools"]["tool_groups"]
|
||||
for group_name, tool_group in tool_groups_entity.items():
|
||||
# Try to get group label from entity
|
||||
group_label = None
|
||||
if hasattr(tool_groups_entity, "get_key_label"):
|
||||
group_label = tool_groups_entity.get_key_label(group_name)
|
||||
|
||||
variants_entity = tool_group["variants"]
|
||||
for variant_name in variants_entity.keys():
|
||||
# Prepare tool name (used as value)
|
||||
tool_name = "/".join((group_name, variant_name))
|
||||
|
||||
# Try to get variant label from entity
|
||||
variant_label = None
|
||||
if hasattr(variants_entity, "get_key_label"):
|
||||
variant_label = variants_entity.get_key_label(variant_name)
|
||||
|
||||
# Tool label that will be shown
|
||||
# - use tool name itself if labels are not filled
|
||||
if group_label and variant_label:
|
||||
tool_label = " ".join((group_label, variant_label))
|
||||
else:
|
||||
tool_label = tool_name
|
||||
|
||||
enum_items.append({tool_name: tool_label})
|
||||
valid_keys.add(tool_name)
|
||||
return enum_items, valid_keys
|
||||
|
||||
def set_override_state(self, *args, **kwargs):
|
||||
super(ToolsEnumEntity, self).set_override_state(*args, **kwargs)
|
||||
|
||||
self.enum_items, self.valid_keys = self._get_enum_values()
|
||||
new_value = []
|
||||
for key in self._current_value:
|
||||
if key in self.valid_keys:
|
||||
new_value.append(key)
|
||||
self._current_value = new_value
|
||||
125
openpype/settings/entities/exceptions.py
Normal file
125
openpype/settings/entities/exceptions.py
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
from openpype.settings.constants import KEY_ALLOWED_SYMBOLS
|
||||
|
||||
|
||||
class DefaultsNotDefined(Exception):
|
||||
def __init__(self, obj):
|
||||
msg = "Default values for object are not set. {}".format(obj.path)
|
||||
super(DefaultsNotDefined, self).__init__(msg)
|
||||
|
||||
|
||||
class StudioDefaultsNotDefined(Exception):
|
||||
def __init__(self, obj):
|
||||
msg = "Studio default values for object are not set. {}".format(
|
||||
obj.path
|
||||
)
|
||||
super(StudioDefaultsNotDefined, self).__init__(msg)
|
||||
|
||||
|
||||
class InvalidValueType(Exception):
|
||||
msg_template = "{}"
|
||||
|
||||
def __init__(self, valid_types, invalid_type, path):
|
||||
msg = "Path \"{}\". ".format(path)
|
||||
|
||||
joined_types = ", ".join(
|
||||
[str(valid_type) for valid_type in valid_types]
|
||||
)
|
||||
msg += "Got invalid type \"{}\". Expected: {}".format(
|
||||
invalid_type, joined_types
|
||||
)
|
||||
self.msg = msg
|
||||
super(InvalidValueType, self).__init__(msg)
|
||||
|
||||
|
||||
class RequiredKeyModified(KeyError):
|
||||
def __init__(self, entity_path, key):
|
||||
msg = "{} - Tried to modify required key \"{}\"."
|
||||
super(RequiredKeyModified, self).__init__(msg.format(entity_path, key))
|
||||
|
||||
|
||||
class InvalidKeySymbols(KeyError):
|
||||
def __init__(self, entity_path, key):
|
||||
msg = "{} - Invalid key \"{}\". Allowed symbols are {}"
|
||||
super(InvalidKeySymbols, self).__init__(
|
||||
msg.format(entity_path, key, KEY_ALLOWED_SYMBOLS)
|
||||
)
|
||||
|
||||
|
||||
class SchemaError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class EntitySchemaError(SchemaError):
|
||||
def __init__(self, entity, reason):
|
||||
self.entity = entity
|
||||
self.reason = reason
|
||||
msg = "{} {} - {}".format(entity.__class__, entity.path, reason)
|
||||
super(EntitySchemaError, self).__init__(msg)
|
||||
|
||||
|
||||
class SchemeGroupHierarchyBug(EntitySchemaError):
|
||||
def __init__(self, entity):
|
||||
reason = (
|
||||
"Items with attribute \"is_group\" can't have another item with"
|
||||
" \"is_group\" attribute as child."
|
||||
)
|
||||
super(SchemeGroupHierarchyBug, self).__init__(entity, reason)
|
||||
|
||||
|
||||
class SchemaMissingFileInfo(SchemaError):
|
||||
def __init__(self, invalid):
|
||||
full_path_keys = []
|
||||
for item in invalid:
|
||||
full_path_keys.append("\"{}\"".format("/".join(item)))
|
||||
|
||||
msg = (
|
||||
"Schema has missing definition of output file (\"is_file\" key)"
|
||||
" for keys. [{}]"
|
||||
).format(", ".join(full_path_keys))
|
||||
super(SchemaMissingFileInfo, self).__init__(msg)
|
||||
|
||||
|
||||
class SchemaDuplicatedKeys(SchemaError):
|
||||
def __init__(self, entity, key):
|
||||
msg = (
|
||||
"Schema item contain duplicated key \"{}\" in"
|
||||
" one hierarchy level."
|
||||
).format(key)
|
||||
super(SchemaDuplicatedKeys, self).__init__(entity, msg)
|
||||
|
||||
|
||||
class SchemaDuplicatedEnvGroupKeys(SchemaError):
|
||||
def __init__(self, invalid):
|
||||
items = []
|
||||
for key_path, keys in invalid.items():
|
||||
joined_keys = ", ".join([
|
||||
"\"{}\"".format(key) for key in keys
|
||||
])
|
||||
items.append("\"{}\" ({})".format(key_path, joined_keys))
|
||||
|
||||
msg = (
|
||||
"Schema items contain duplicated environment group keys. {}"
|
||||
).format(" || ".join(items))
|
||||
super(SchemaDuplicatedEnvGroupKeys, self).__init__(msg)
|
||||
|
||||
|
||||
class SchemaTemplateMissingKeys(SchemaError):
|
||||
def __init__(self, missing_keys, required_keys, template_name=None):
|
||||
self.missing_keys = missing_keys
|
||||
self.required_keys = required_keys
|
||||
if template_name:
|
||||
msg = "Schema template \"{}\" require more keys.\n".format(
|
||||
template_name
|
||||
)
|
||||
else:
|
||||
msg = ""
|
||||
msg += "Required keys: {}\nMissing keys: {}".format(
|
||||
self.join_keys(required_keys),
|
||||
self.join_keys(missing_keys)
|
||||
)
|
||||
super(SchemaTemplateMissingKeys, self).__init__(msg)
|
||||
|
||||
def join_keys(self, keys):
|
||||
return ", ".join([
|
||||
"\"{}\"".format(key) for key in keys
|
||||
])
|
||||
513
openpype/settings/entities/input_entities.py
Normal file
513
openpype/settings/entities/input_entities.py
Normal file
|
|
@ -0,0 +1,513 @@
|
|||
import re
|
||||
import copy
|
||||
from abc import abstractmethod
|
||||
|
||||
from .base_entity import ItemEntity
|
||||
from .lib import (
|
||||
NOT_SET,
|
||||
STRING_TYPE,
|
||||
OverrideState
|
||||
)
|
||||
from .exceptions import (
|
||||
DefaultsNotDefined,
|
||||
StudioDefaultsNotDefined,
|
||||
EntitySchemaError
|
||||
)
|
||||
|
||||
from openpype.settings.constants import (
|
||||
METADATA_KEYS,
|
||||
M_ENVIRONMENT_KEY
|
||||
)
|
||||
|
||||
|
||||
class EndpointEntity(ItemEntity):
|
||||
"""Entity that is a endpoint of settings value.
|
||||
|
||||
In most of cases endpoint entity does not have children entities and if has
|
||||
then they are dynamic and can be removed/created. Is automatically set as
|
||||
group if any parent is not, that is because of override metadata.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(EndpointEntity, self).__init__(*args, **kwargs)
|
||||
|
||||
if (
|
||||
not (self.group_item or self.is_group)
|
||||
and not (self.is_dynamic_item or self.is_in_dynamic_item)
|
||||
):
|
||||
self.is_group = True
|
||||
|
||||
def schema_validations(self):
|
||||
"""Validation of entity schema and schema hierarchy."""
|
||||
# Default value when even defaults are not filled must be set
|
||||
if self.value_on_not_set is NOT_SET:
|
||||
reason = "Attribute `value_on_not_set` is not filled. {}".format(
|
||||
self.__class__.__name__
|
||||
)
|
||||
raise EntitySchemaError(self, reason)
|
||||
|
||||
super(EndpointEntity, self).schema_validations()
|
||||
|
||||
@abstractmethod
|
||||
def _settings_value(self):
|
||||
pass
|
||||
|
||||
def settings_value(self):
|
||||
if self._override_state is OverrideState.NOT_DEFINED:
|
||||
return NOT_SET
|
||||
|
||||
if self.is_group:
|
||||
if self._override_state is OverrideState.STUDIO:
|
||||
if not self.has_studio_override:
|
||||
return NOT_SET
|
||||
elif self._override_state is OverrideState.PROJECT:
|
||||
if not self.has_project_override:
|
||||
return NOT_SET
|
||||
return self._settings_value()
|
||||
|
||||
def on_change(self):
|
||||
for callback in self.on_change_callbacks:
|
||||
callback()
|
||||
self.parent.on_child_change(self)
|
||||
|
||||
def update_default_value(self, value):
|
||||
value = self._check_update_value(value, "default")
|
||||
self._default_value = value
|
||||
self.has_default_value = value is not NOT_SET
|
||||
|
||||
def update_studio_value(self, value):
|
||||
value = self._check_update_value(value, "studio override")
|
||||
self._studio_override_value = value
|
||||
self.had_studio_override = bool(value is not NOT_SET)
|
||||
|
||||
def update_project_value(self, value):
|
||||
value = self._check_update_value(value, "project override")
|
||||
self._project_override_value = value
|
||||
self.had_project_override = bool(value is not NOT_SET)
|
||||
|
||||
|
||||
class InputEntity(EndpointEntity):
|
||||
"""Endpoint entity without children."""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(InputEntity, self).__init__(*args, **kwargs)
|
||||
self._value_is_modified = False
|
||||
self._current_value = NOT_SET
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, ItemEntity):
|
||||
return self.value == other.value
|
||||
return self.value == other
|
||||
|
||||
def get_child_path(self, child_obj):
|
||||
raise TypeError("{} can't have children".format(
|
||||
self.__class__.__name__
|
||||
))
|
||||
|
||||
def schema_validations(self):
|
||||
# Input entity must have file parent.
|
||||
if not self.file_item:
|
||||
raise EntitySchemaError(self, "Missing parent file entity.")
|
||||
|
||||
super(InputEntity, self).schema_validations()
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
"""Entity's value without metadata."""
|
||||
return self._current_value
|
||||
|
||||
def _settings_value(self):
|
||||
return copy.deepcopy(self.value)
|
||||
|
||||
def set(self, value):
|
||||
"""Change value."""
|
||||
self._current_value = self.convert_to_valid_type(value)
|
||||
self._on_value_change()
|
||||
|
||||
def _on_value_change(self):
|
||||
# Change has_project_override attr value
|
||||
if self._override_state is OverrideState.PROJECT:
|
||||
self._has_project_override = True
|
||||
|
||||
elif self._override_state is OverrideState.STUDIO:
|
||||
self._has_studio_override = True
|
||||
|
||||
self.on_change()
|
||||
|
||||
def on_change(self):
|
||||
"""Callback triggered on change.
|
||||
|
||||
There are cases when this method may be called from other entity.
|
||||
"""
|
||||
value_is_modified = None
|
||||
if self._override_state is OverrideState.PROJECT:
|
||||
# Only value change
|
||||
if (
|
||||
self._has_project_override
|
||||
and self._project_override_value is not NOT_SET
|
||||
):
|
||||
value_is_modified = (
|
||||
self._current_value != self._project_override_value
|
||||
)
|
||||
|
||||
if (
|
||||
self._override_state is OverrideState.STUDIO
|
||||
or value_is_modified is None
|
||||
):
|
||||
if (
|
||||
self._has_studio_override
|
||||
and self._studio_override_value is not NOT_SET
|
||||
):
|
||||
value_is_modified = (
|
||||
self._current_value != self._studio_override_value
|
||||
)
|
||||
|
||||
if value_is_modified is None:
|
||||
value_is_modified = self._current_value != self._default_value
|
||||
|
||||
self._value_is_modified = value_is_modified
|
||||
|
||||
super(InputEntity, self).on_change()
|
||||
|
||||
def on_child_change(self, child_obj):
|
||||
raise TypeError("Input entities do not contain children.")
|
||||
|
||||
@property
|
||||
def has_unsaved_changes(self):
|
||||
if self._override_state is OverrideState.NOT_DEFINED:
|
||||
return False
|
||||
|
||||
if self._value_is_modified:
|
||||
return True
|
||||
|
||||
# These may be stored on value change
|
||||
if self._override_state is OverrideState.DEFAULTS:
|
||||
if not self.has_default_value:
|
||||
return True
|
||||
|
||||
elif self._override_state is OverrideState.STUDIO:
|
||||
if self._has_studio_override != self.had_studio_override:
|
||||
return True
|
||||
|
||||
if not self._has_studio_override and not self.has_default_value:
|
||||
return True
|
||||
|
||||
elif self._override_state is OverrideState.PROJECT:
|
||||
if self._has_project_override != self.had_project_override:
|
||||
return True
|
||||
|
||||
if (
|
||||
not self._has_project_override
|
||||
and not self._has_studio_override
|
||||
and not self.has_default_value
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_override_state(self, state):
|
||||
# Trigger override state change of root if is not same
|
||||
if self.root_item.override_state is not state:
|
||||
self.root_item.set_override_state(state)
|
||||
return
|
||||
|
||||
self._override_state = state
|
||||
# Ignore if is dynamic item and use default in that case
|
||||
if not self.is_dynamic_item and not self.is_in_dynamic_item:
|
||||
if state > OverrideState.DEFAULTS:
|
||||
if not self.has_default_value:
|
||||
raise DefaultsNotDefined(self)
|
||||
|
||||
elif state > OverrideState.STUDIO:
|
||||
if not self.had_studio_override:
|
||||
raise StudioDefaultsNotDefined(self)
|
||||
|
||||
if state is OverrideState.STUDIO:
|
||||
self._has_studio_override = (
|
||||
self._studio_override_value is not NOT_SET
|
||||
)
|
||||
|
||||
elif state is OverrideState.PROJECT:
|
||||
self._has_project_override = (
|
||||
self._project_override_value is not NOT_SET
|
||||
)
|
||||
self._has_studio_override = self.had_studio_override
|
||||
|
||||
value = NOT_SET
|
||||
if state is OverrideState.PROJECT:
|
||||
value = self._project_override_value
|
||||
|
||||
if value is NOT_SET and state >= OverrideState.STUDIO:
|
||||
value = self._studio_override_value
|
||||
|
||||
if value is NOT_SET and state >= OverrideState.DEFAULTS:
|
||||
value = self._default_value
|
||||
|
||||
if value is NOT_SET:
|
||||
value = self.value_on_not_set
|
||||
self.has_default_value = False
|
||||
else:
|
||||
self.has_default_value = True
|
||||
self._value_is_modified = False
|
||||
|
||||
self._current_value = copy.deepcopy(value)
|
||||
|
||||
def _discard_changes(self, on_change_trigger=None):
|
||||
self._value_is_modified = False
|
||||
if self._override_state >= OverrideState.PROJECT:
|
||||
self._has_project_override = self.had_project_override
|
||||
if self.had_project_override:
|
||||
self._current_value = copy.deepcopy(
|
||||
self._project_override_value
|
||||
)
|
||||
on_change_trigger.append(self.on_change)
|
||||
return
|
||||
|
||||
if self._override_state >= OverrideState.STUDIO:
|
||||
self._has_studio_override = self.had_studio_override
|
||||
if self.had_studio_override:
|
||||
self._current_value = copy.deepcopy(
|
||||
self._studio_override_value
|
||||
)
|
||||
on_change_trigger.append(self.on_change)
|
||||
return
|
||||
|
||||
if self._override_state >= OverrideState.DEFAULTS:
|
||||
if self.has_default_value:
|
||||
value = self._default_value
|
||||
else:
|
||||
value = self.value_on_not_set
|
||||
self._current_value = copy.deepcopy(value)
|
||||
on_change_trigger.append(self.on_change)
|
||||
return
|
||||
|
||||
raise NotImplementedError("BUG: Unexcpected part of code.")
|
||||
|
||||
def _add_to_studio_default(self, _on_change_trigger):
|
||||
self._has_studio_override = True
|
||||
self.on_change()
|
||||
|
||||
def _remove_from_studio_default(self, on_change_trigger):
|
||||
value = self._default_value
|
||||
if value is NOT_SET:
|
||||
value = self.value_on_not_set
|
||||
self._current_value = copy.deepcopy(value)
|
||||
|
||||
self._has_studio_override = False
|
||||
self._value_is_modified = False
|
||||
|
||||
on_change_trigger.append(self.on_change)
|
||||
|
||||
def _add_to_project_override(self, _on_change_trigger):
|
||||
self._has_project_override = True
|
||||
self.on_change()
|
||||
|
||||
def _remove_from_project_override(self, on_change_trigger):
|
||||
if self._override_state is not OverrideState.PROJECT:
|
||||
return
|
||||
|
||||
if not self._has_project_override:
|
||||
return
|
||||
|
||||
self._has_project_override = False
|
||||
if self._has_studio_override:
|
||||
current_value = self._studio_override_value
|
||||
elif self.has_default_value:
|
||||
current_value = self._default_value
|
||||
else:
|
||||
current_value = self.value_on_not_set
|
||||
|
||||
self._current_value = copy.deepcopy(current_value)
|
||||
on_change_trigger.append(self.on_change)
|
||||
|
||||
|
||||
class NumberEntity(InputEntity):
|
||||
schema_types = ["number"]
|
||||
float_number_regex = re.compile(r"^\d+\.\d+$")
|
||||
int_number_regex = re.compile(r"^\d+$")
|
||||
|
||||
def _item_initalization(self):
|
||||
self.minimum = self.schema_data.get("minimum", -99999)
|
||||
self.maximum = self.schema_data.get("maximum", 99999)
|
||||
self.decimal = self.schema_data.get("decimal", 0)
|
||||
|
||||
value_on_not_set = self.schema_data.get("default", 0)
|
||||
if self.decimal:
|
||||
valid_value_types = (float, )
|
||||
value_on_not_set = float(value_on_not_set)
|
||||
else:
|
||||
valid_value_types = (int, )
|
||||
value_on_not_set = int(value_on_not_set)
|
||||
self.valid_value_types = valid_value_types
|
||||
self.value_on_not_set = value_on_not_set
|
||||
|
||||
def _convert_to_valid_type(self, value):
|
||||
if isinstance(value, str):
|
||||
new_value = None
|
||||
if self.float_number_regex.match(value):
|
||||
new_value = float(value)
|
||||
elif self.int_number_regex.match(value):
|
||||
new_value = int(value)
|
||||
|
||||
if new_value is not None:
|
||||
self.log.info("{} - Converted str {} to {} {}".format(
|
||||
self.path, value, type(new_value).__name__, new_value
|
||||
))
|
||||
value = new_value
|
||||
|
||||
if self.decimal:
|
||||
if isinstance(value, float):
|
||||
return value
|
||||
if isinstance(value, int):
|
||||
return float(value)
|
||||
else:
|
||||
if isinstance(value, int):
|
||||
return value
|
||||
if isinstance(value, float):
|
||||
new_value = int(value)
|
||||
if new_value != value:
|
||||
self.log.info("{} - Converted float {} to int {}".format(
|
||||
self.path, value, new_value
|
||||
))
|
||||
return new_value
|
||||
return NOT_SET
|
||||
|
||||
|
||||
class BoolEntity(InputEntity):
|
||||
schema_types = ["boolean"]
|
||||
|
||||
def _item_initalization(self):
|
||||
self.valid_value_types = (bool, )
|
||||
self.value_on_not_set = True
|
||||
|
||||
|
||||
class TextEntity(InputEntity):
|
||||
schema_types = ["text"]
|
||||
|
||||
def _item_initalization(self):
|
||||
self.valid_value_types = (STRING_TYPE, )
|
||||
self.value_on_not_set = ""
|
||||
|
||||
# GUI attributes
|
||||
self.multiline = self.schema_data.get("multiline", False)
|
||||
self.placeholder_text = self.schema_data.get("placeholder")
|
||||
|
||||
def _convert_to_valid_type(self, value):
|
||||
# Allow numbers converted to string
|
||||
if isinstance(value, (int, float)):
|
||||
return str(value)
|
||||
return NOT_SET
|
||||
|
||||
|
||||
class PathInput(InputEntity):
|
||||
schema_types = ["path-input"]
|
||||
|
||||
def _item_initalization(self):
|
||||
self.valid_value_types = (STRING_TYPE, )
|
||||
self.value_on_not_set = ""
|
||||
|
||||
|
||||
class RawJsonEntity(InputEntity):
|
||||
schema_types = ["raw-json"]
|
||||
|
||||
def _item_initalization(self):
|
||||
# Schema must define if valid value is dict or list
|
||||
is_list = self.schema_data.get("is_list", False)
|
||||
if is_list:
|
||||
valid_value_types = (list, )
|
||||
value_on_not_set = []
|
||||
else:
|
||||
valid_value_types = (dict, )
|
||||
value_on_not_set = {}
|
||||
|
||||
self._is_list = is_list
|
||||
self.valid_value_types = valid_value_types
|
||||
self.value_on_not_set = value_on_not_set
|
||||
|
||||
self.default_metadata = {}
|
||||
self.studio_override_metadata = {}
|
||||
self.project_override_metadata = {}
|
||||
|
||||
@property
|
||||
def is_list(self):
|
||||
return self._is_list
|
||||
|
||||
@property
|
||||
def is_dict(self):
|
||||
return not self._is_list
|
||||
|
||||
def set(self, value):
|
||||
new_value = self.convert_to_valid_type(value)
|
||||
|
||||
if isinstance(new_value, dict):
|
||||
for key in METADATA_KEYS:
|
||||
if key in new_value:
|
||||
new_value.pop(key)
|
||||
self._current_value = new_value
|
||||
self._on_value_change()
|
||||
|
||||
@property
|
||||
def metadata(self):
|
||||
output = {}
|
||||
if isinstance(self._current_value, dict) and self.is_env_group:
|
||||
output[M_ENVIRONMENT_KEY] = {
|
||||
self.env_group_key: list(self._current_value.keys())
|
||||
}
|
||||
|
||||
return output
|
||||
|
||||
@property
|
||||
def has_unsaved_changes(self):
|
||||
result = super(RawJsonEntity, self).has_unsaved_changes
|
||||
if not result:
|
||||
result = self.metadata != self._metadata_for_current_state()
|
||||
return result
|
||||
|
||||
def _metadata_for_current_state(self):
|
||||
if (
|
||||
self._override_state is OverrideState.PROJECT
|
||||
and self._project_override_value is not NOT_SET
|
||||
):
|
||||
return self.project_override_metadata
|
||||
|
||||
if (
|
||||
self._override_state >= OverrideState.STUDIO
|
||||
and self._studio_override_value is not NOT_SET
|
||||
):
|
||||
return self.studio_override_metadata
|
||||
|
||||
return self.default_metadata
|
||||
|
||||
def _settings_value(self):
|
||||
value = super(RawJsonEntity, self)._settings_value()
|
||||
if self.is_env_group and isinstance(value, dict):
|
||||
value.update(self.metadata)
|
||||
return value
|
||||
|
||||
def _prepare_value(self, value):
|
||||
metadata = {}
|
||||
if isinstance(value, dict):
|
||||
value = copy.deepcopy(value)
|
||||
for key in METADATA_KEYS:
|
||||
if key in value:
|
||||
metadata[key] = value.pop(key)
|
||||
return value, metadata
|
||||
|
||||
def update_default_value(self, value):
|
||||
value = self._check_update_value(value, "default")
|
||||
self.has_default_value = value is not NOT_SET
|
||||
value, metadata = self._prepare_value(value)
|
||||
self._default_value = value
|
||||
self.default_metadata = metadata
|
||||
|
||||
def update_studio_value(self, value):
|
||||
value = self._check_update_value(value, "studio override")
|
||||
self.had_studio_override = value is not NOT_SET
|
||||
value, metadata = self._prepare_value(value)
|
||||
self._studio_override_value = value
|
||||
self.studio_override_metadata = metadata
|
||||
|
||||
def update_project_value(self, value):
|
||||
value = self._check_update_value(value, "project override")
|
||||
self.had_project_override = value is not NOT_SET
|
||||
value, metadata = self._prepare_value(value)
|
||||
self._project_override_value = value
|
||||
self.project_override_metadata = metadata
|
||||
456
openpype/settings/entities/item_entities.py
Normal file
456
openpype/settings/entities/item_entities.py
Normal file
|
|
@ -0,0 +1,456 @@
|
|||
from .lib import (
|
||||
NOT_SET,
|
||||
STRING_TYPE,
|
||||
OverrideState
|
||||
)
|
||||
from .exceptions import (
|
||||
DefaultsNotDefined,
|
||||
StudioDefaultsNotDefined,
|
||||
EntitySchemaError
|
||||
)
|
||||
from .base_entity import ItemEntity
|
||||
|
||||
|
||||
class PathEntity(ItemEntity):
|
||||
schema_types = ["path"]
|
||||
platforms = ("windows", "darwin", "linux")
|
||||
platform_labels_mapping = {
|
||||
"windows": "Windows",
|
||||
"darwin": "MacOS",
|
||||
"linux": "Linux"
|
||||
}
|
||||
path_item_type_error = "Got invalid path value type {}. Expected: {}"
|
||||
attribute_error_msg = (
|
||||
"'PathEntity' has no attribute '{}' if is not set as multiplatform"
|
||||
)
|
||||
|
||||
def __setitem__(self, *args, **kwargs):
|
||||
return self.child_obj.__setitem__(*args, **kwargs)
|
||||
|
||||
def __getitem__(self, *args, **kwargs):
|
||||
return self.child_obj.__getitem__(*args, **kwargs)
|
||||
|
||||
def __iter__(self):
|
||||
return self.child_obj.__iter__()
|
||||
|
||||
def keys(self):
|
||||
if not self.multiplatform:
|
||||
raise AttributeError(self.attribute_error_msg.format("keys"))
|
||||
return self.child_obj.keys()
|
||||
|
||||
def values(self):
|
||||
if not self.multiplatform:
|
||||
raise AttributeError(self.attribute_error_msg.format("values"))
|
||||
return self.child_obj.values()
|
||||
|
||||
def items(self):
|
||||
if not self.multiplatform:
|
||||
raise AttributeError(self.attribute_error_msg.format("items"))
|
||||
return self.child_obj.items()
|
||||
|
||||
def _item_initalization(self):
|
||||
if not self.group_item and not self.is_group:
|
||||
self.is_group = True
|
||||
|
||||
self.multiplatform = self.schema_data.get("multiplatform", False)
|
||||
self.multipath = self.schema_data.get("multipath", False)
|
||||
|
||||
# Create child object
|
||||
if not self.multiplatform and not self.multipath:
|
||||
valid_value_types = (STRING_TYPE, )
|
||||
item_schema = {
|
||||
"type": "path-input",
|
||||
"key": self.key
|
||||
}
|
||||
|
||||
elif not self.multiplatform:
|
||||
valid_value_types = (list, )
|
||||
item_schema = {
|
||||
"type": "list",
|
||||
"key": self.key,
|
||||
"object_type": "path-input"
|
||||
}
|
||||
|
||||
else:
|
||||
valid_value_types = (dict, )
|
||||
item_schema = {
|
||||
"type": "dict",
|
||||
"key": self.key,
|
||||
"show_borders": False,
|
||||
"children": []
|
||||
}
|
||||
for platform_key in self.platforms:
|
||||
platform_label = self.platform_labels_mapping[platform_key]
|
||||
child_item = {
|
||||
"key": platform_key,
|
||||
"label": platform_label
|
||||
}
|
||||
if self.multipath:
|
||||
child_item["type"] = "list"
|
||||
child_item["object_type"] = "path-input"
|
||||
else:
|
||||
child_item["type"] = "path-input"
|
||||
|
||||
item_schema["children"].append(child_item)
|
||||
|
||||
self.valid_value_types = valid_value_types
|
||||
self.child_obj = self.create_schema_object(item_schema, self)
|
||||
|
||||
def get_child_path(self, _child_obj):
|
||||
return self.path
|
||||
|
||||
def set(self, value):
|
||||
self.child_obj.set(value)
|
||||
|
||||
def settings_value(self):
|
||||
if self._override_state is OverrideState.NOT_DEFINED:
|
||||
return NOT_SET
|
||||
|
||||
if self.is_group:
|
||||
if self._override_state is OverrideState.STUDIO:
|
||||
if not self.has_studio_override:
|
||||
return NOT_SET
|
||||
elif self._override_state is OverrideState.PROJECT:
|
||||
if not self.has_project_override:
|
||||
return NOT_SET
|
||||
|
||||
return self.child_obj.settings_value()
|
||||
|
||||
def on_change(self):
|
||||
for callback in self.on_change_callbacks:
|
||||
callback()
|
||||
self.parent.on_child_change(self)
|
||||
|
||||
def on_child_change(self, _child_obj):
|
||||
self.on_change()
|
||||
|
||||
@property
|
||||
def has_unsaved_changes(self):
|
||||
return self.child_obj.has_unsaved_changes
|
||||
|
||||
@property
|
||||
def has_studio_override(self):
|
||||
return self.child_obj.has_studio_override
|
||||
|
||||
@property
|
||||
def has_project_override(self):
|
||||
return self.child_obj.has_project_override
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self.child_obj.value
|
||||
|
||||
def set_override_state(self, state):
|
||||
# Trigger override state change of root if is not same
|
||||
if self.root_item.override_state is not state:
|
||||
self.root_item.set_override_state(state)
|
||||
return
|
||||
|
||||
self._override_state = state
|
||||
self.child_obj.set_override_state(state)
|
||||
|
||||
def update_default_value(self, value):
|
||||
self.child_obj.update_default_value(value)
|
||||
|
||||
def update_project_value(self, value):
|
||||
self.child_obj.update_project_value(value)
|
||||
|
||||
def update_studio_value(self, value):
|
||||
self.child_obj.update_studio_value(value)
|
||||
|
||||
def _discard_changes(self, *args, **kwargs):
|
||||
self.child_obj.discard_changes(*args, **kwargs)
|
||||
|
||||
def _add_to_studio_default(self, *args, **kwargs):
|
||||
self.child_obj.add_to_studio_default(*args, **kwargs)
|
||||
|
||||
def _remove_from_studio_default(self, *args, **kwargs):
|
||||
self.child_obj.remove_from_studio_default(*args, **kwargs)
|
||||
|
||||
def _add_to_project_override(self, *args, **kwargs):
|
||||
self.child_obj.add_to_project_override(*args, **kwargs)
|
||||
|
||||
def _remove_from_project_override(self, *args, **kwargs):
|
||||
self.child_obj.remove_from_project_override(*args, **kwargs)
|
||||
|
||||
def reset_callbacks(self):
|
||||
super(PathEntity, self).reset_callbacks()
|
||||
self.child_obj.reset_callbacks()
|
||||
|
||||
|
||||
class ListStrictEntity(ItemEntity):
|
||||
schema_types = ["list-strict"]
|
||||
|
||||
def _item_initalization(self):
|
||||
self.valid_value_types = (list, )
|
||||
self.require_key = True
|
||||
|
||||
self.initial_value = None
|
||||
|
||||
self._ignore_child_changes = False
|
||||
|
||||
# Child items
|
||||
self.object_types = self.schema_data["object_types"]
|
||||
|
||||
self.children = []
|
||||
for children_schema in self.object_types:
|
||||
child_obj = self.create_schema_object(children_schema, self, True)
|
||||
self.children.append(child_obj)
|
||||
|
||||
# GUI attribute
|
||||
self.is_horizontal = self.schema_data.get("horizontal", True)
|
||||
if not self.group_item and not self.is_group:
|
||||
self.is_group = True
|
||||
|
||||
def schema_validations(self):
|
||||
# List entity must have file parent.
|
||||
if not self.file_item and not self.is_file:
|
||||
raise EntitySchemaError(
|
||||
self, "Missing file entity in hierarchy."
|
||||
)
|
||||
|
||||
super(ListStrictEntity, self).schema_validations()
|
||||
|
||||
def get_child_path(self, child_obj):
|
||||
result_idx = None
|
||||
for idx, _child_obj in enumerate(self.children):
|
||||
if _child_obj is child_obj:
|
||||
result_idx = idx
|
||||
break
|
||||
|
||||
if result_idx is None:
|
||||
raise ValueError("Didn't found child {}".format(child_obj))
|
||||
|
||||
return "/".join([self.path, str(result_idx)])
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
output = []
|
||||
for child_obj in self.children:
|
||||
output.append(child_obj.value)
|
||||
return output
|
||||
|
||||
def set(self, value):
|
||||
new_value = self.convert_to_valid_type(value)
|
||||
for idx, item in enumerate(new_value):
|
||||
self.children[idx].set(item)
|
||||
|
||||
def settings_value(self):
|
||||
if self._override_state is OverrideState.NOT_DEFINED:
|
||||
return NOT_SET
|
||||
|
||||
if (
|
||||
self.is_group
|
||||
and self._override_state is not OverrideState.DEFAULTS
|
||||
):
|
||||
if self._override_state is OverrideState.STUDIO:
|
||||
if not self.has_studio_override:
|
||||
return NOT_SET
|
||||
elif self._override_state is OverrideState.PROJECT:
|
||||
if not self.has_project_override:
|
||||
return NOT_SET
|
||||
|
||||
output = []
|
||||
for child_obj in self.children:
|
||||
output.append(child_obj.settings_value())
|
||||
return output
|
||||
|
||||
def on_change(self):
|
||||
for callback in self.on_change_callbacks:
|
||||
callback()
|
||||
self.parent.on_child_change(self)
|
||||
|
||||
def on_child_change(self, _child_obj):
|
||||
if self._ignore_child_changes:
|
||||
return
|
||||
|
||||
if self._override_state is OverrideState.STUDIO:
|
||||
self._has_studio_override = self._child_has_studio_override
|
||||
elif self._override_state is OverrideState.PROJECT:
|
||||
self._has_project_override = self._child_has_project_override
|
||||
|
||||
self.on_change()
|
||||
|
||||
@property
|
||||
def has_unsaved_changes(self):
|
||||
if self._override_state is OverrideState.NOT_DEFINED:
|
||||
return False
|
||||
|
||||
if self._override_state is OverrideState.DEFAULTS:
|
||||
if not self.has_default_value:
|
||||
return True
|
||||
|
||||
elif self._override_state is OverrideState.STUDIO:
|
||||
if self.had_studio_override != self._has_studio_override:
|
||||
return True
|
||||
|
||||
if not self._has_studio_override and not self.has_default_value:
|
||||
return True
|
||||
|
||||
elif self._override_state is OverrideState.PROJECT:
|
||||
if self.had_project_override != self._has_project_override:
|
||||
return True
|
||||
|
||||
if (
|
||||
not self._has_project_override
|
||||
and not self._has_studio_override
|
||||
and not self.has_default_value
|
||||
):
|
||||
return True
|
||||
|
||||
if self._child_has_unsaved_changes:
|
||||
return True
|
||||
|
||||
if self.settings_value() != self.initial_value:
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def has_studio_override(self):
|
||||
return self._has_studio_override or self._child_has_studio_override
|
||||
|
||||
@property
|
||||
def has_project_override(self):
|
||||
return self._has_project_override or self._child_has_project_override
|
||||
|
||||
@property
|
||||
def _child_has_unsaved_changes(self):
|
||||
for child_obj in self.children:
|
||||
if child_obj.has_unsaved_changes:
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def _child_has_studio_override(self):
|
||||
for child_obj in self.children:
|
||||
if child_obj.has_studio_override:
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def _child_has_project_override(self):
|
||||
for child_obj in self.children:
|
||||
if child_obj.has_project_override:
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_override_state(self, state):
|
||||
# Trigger override state change of root if is not same
|
||||
if self.root_item.override_state is not state:
|
||||
self.root_item.set_override_state(state)
|
||||
return
|
||||
|
||||
self._override_state = state
|
||||
# Ignore if is dynamic item and use default in that case
|
||||
if not self.is_dynamic_item and not self.is_in_dynamic_item:
|
||||
if state > OverrideState.DEFAULTS:
|
||||
if not self.has_default_value:
|
||||
raise DefaultsNotDefined(self)
|
||||
|
||||
elif state > OverrideState.STUDIO:
|
||||
if not self.had_studio_override:
|
||||
raise StudioDefaultsNotDefined(self)
|
||||
|
||||
for child_entity in self.children:
|
||||
child_entity.set_override_state(state)
|
||||
|
||||
self.initial_value = self.settings_value()
|
||||
|
||||
def _discard_changes(self, on_change_trigger):
|
||||
for child_obj in self.children:
|
||||
child_obj.discard_changes(on_change_trigger)
|
||||
|
||||
def _add_to_studio_default(self, _on_change_trigger):
|
||||
self._has_studio_override = True
|
||||
self.on_change()
|
||||
|
||||
def _remove_from_studio_default(self, on_change_trigger):
|
||||
self._ignore_child_changes = True
|
||||
|
||||
for child_obj in self.children:
|
||||
child_obj.remove_from_studio_default(on_change_trigger)
|
||||
|
||||
self._ignore_child_changes = False
|
||||
|
||||
self._has_studio_override = False
|
||||
|
||||
def _add_to_project_override(self, _on_change_trigger):
|
||||
self._has_project_override = True
|
||||
self.on_change()
|
||||
|
||||
def _remove_from_project_override(self, on_change_trigger):
|
||||
self._ignore_child_changes = True
|
||||
|
||||
for child_obj in self.children:
|
||||
child_obj.remove_from_project_override(on_change_trigger)
|
||||
|
||||
self._ignore_child_changes = False
|
||||
|
||||
self._has_project_override = False
|
||||
|
||||
def _check_update_value(self, value, value_type):
|
||||
value = super(ListStrictEntity, self)._check_update_value(
|
||||
value, value_type
|
||||
)
|
||||
if value is NOT_SET:
|
||||
return value
|
||||
|
||||
child_len = len(self.children)
|
||||
value_len = len(value)
|
||||
if value_len == child_len:
|
||||
return value
|
||||
|
||||
self.log.warning(
|
||||
(
|
||||
"{} Amount of strict list items in {} values is"
|
||||
" not same as expected. Expected {} items. Got {} items. {}"
|
||||
).format(
|
||||
self.path, value_type,
|
||||
child_len, value_len, str(value)
|
||||
)
|
||||
)
|
||||
|
||||
if value_len < child_len:
|
||||
# Fill missing values with NOT_SET
|
||||
for _ in range(child_len - value_len):
|
||||
value.append(NOT_SET)
|
||||
else:
|
||||
# Pop values that are overloaded
|
||||
for _ in range(value_len - child_len):
|
||||
value.pop(child_len)
|
||||
return value
|
||||
|
||||
def update_default_value(self, value):
|
||||
value = self._check_update_value(value, "default")
|
||||
self.has_default_value = value is not NOT_SET
|
||||
if value is NOT_SET:
|
||||
for child_obj in self.children:
|
||||
child_obj.update_default_value(value)
|
||||
|
||||
else:
|
||||
for idx, item_value in enumerate(value):
|
||||
self.children[idx].update_default_value(item_value)
|
||||
|
||||
def update_studio_value(self, value):
|
||||
value = self._check_update_value(value, "studio override")
|
||||
if value is NOT_SET:
|
||||
for child_obj in self.children:
|
||||
child_obj.update_studio_value(value)
|
||||
|
||||
else:
|
||||
for idx, item_value in enumerate(value):
|
||||
self.children[idx].update_studio_value(item_value)
|
||||
|
||||
def update_project_value(self, value):
|
||||
value = self._check_update_value(value, "project override")
|
||||
if value is NOT_SET:
|
||||
for child_obj in self.children:
|
||||
child_obj.update_project_value(value)
|
||||
|
||||
else:
|
||||
for idx, item_value in enumerate(value):
|
||||
self.children[idx].update_project_value(item_value)
|
||||
|
||||
def reset_callbacks(self):
|
||||
super(ListStrictEntity, self).reset_callbacks()
|
||||
self.child_obj.reset_callbacks()
|
||||
355
openpype/settings/entities/lib.py
Normal file
355
openpype/settings/entities/lib.py
Normal file
|
|
@ -0,0 +1,355 @@
|
|||
import os
|
||||
import re
|
||||
import json
|
||||
import copy
|
||||
|
||||
from .exceptions import (
|
||||
SchemaTemplateMissingKeys,
|
||||
SchemaDuplicatedEnvGroupKeys
|
||||
)
|
||||
|
||||
try:
|
||||
STRING_TYPE = basestring
|
||||
except Exception:
|
||||
STRING_TYPE = str
|
||||
|
||||
WRAPPER_TYPES = ["form", "collapsible-wrap"]
|
||||
NOT_SET = type("NOT_SET", (), {"__bool__": lambda obj: False})()
|
||||
OVERRIDE_VERSION = 1
|
||||
|
||||
template_key_pattern = re.compile(r"(\{.*?[^{0]*\})")
|
||||
|
||||
|
||||
def _fill_schema_template_data(
|
||||
template, template_data, required_keys=None, missing_keys=None
|
||||
):
|
||||
first = False
|
||||
if required_keys is None:
|
||||
first = True
|
||||
required_keys = set()
|
||||
missing_keys = set()
|
||||
|
||||
_template = []
|
||||
default_values = {}
|
||||
for item in template:
|
||||
if isinstance(item, dict) and "__default_values__" in item:
|
||||
default_values = item["__default_values__"]
|
||||
else:
|
||||
_template.append(item)
|
||||
template = _template
|
||||
|
||||
for key, value in default_values.items():
|
||||
if key not in template_data:
|
||||
template_data[key] = value
|
||||
|
||||
if not template:
|
||||
output = template
|
||||
|
||||
elif isinstance(template, list):
|
||||
output = []
|
||||
for item in template:
|
||||
output.append(_fill_schema_template_data(
|
||||
item, template_data, required_keys, missing_keys
|
||||
))
|
||||
|
||||
elif isinstance(template, dict):
|
||||
output = {}
|
||||
for key, value in template.items():
|
||||
output[key] = _fill_schema_template_data(
|
||||
value, template_data, required_keys, missing_keys
|
||||
)
|
||||
|
||||
elif isinstance(template, STRING_TYPE):
|
||||
# TODO find much better way how to handle filling template data
|
||||
for replacement_string in template_key_pattern.findall(template):
|
||||
key = str(replacement_string[1:-1])
|
||||
required_keys.add(key)
|
||||
if key not in template_data:
|
||||
missing_keys.add(key)
|
||||
continue
|
||||
|
||||
value = template_data[key]
|
||||
if replacement_string == template:
|
||||
# Replace the value with value from templates data
|
||||
# - with this is possible to set value with different type
|
||||
template = value
|
||||
else:
|
||||
# Only replace the key in string
|
||||
template = template.replace(replacement_string, value)
|
||||
output = template
|
||||
|
||||
else:
|
||||
output = template
|
||||
|
||||
if first and missing_keys:
|
||||
raise SchemaTemplateMissingKeys(missing_keys, required_keys)
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def _fill_schema_template(child_data, schema_collection, schema_templates):
|
||||
template_name = child_data["name"]
|
||||
template = schema_templates.get(template_name)
|
||||
if template is None:
|
||||
if template_name in schema_collection:
|
||||
raise KeyError((
|
||||
"Schema \"{}\" is used as `schema_template`"
|
||||
).format(template_name))
|
||||
raise KeyError("Schema template \"{}\" was not found".format(
|
||||
template_name
|
||||
))
|
||||
|
||||
# Default value must be dictionary (NOT list)
|
||||
# - empty list would not add any item if `template_data` are not filled
|
||||
template_data = child_data.get("template_data") or {}
|
||||
if isinstance(template_data, dict):
|
||||
template_data = [template_data]
|
||||
|
||||
output = []
|
||||
for single_template_data in template_data:
|
||||
try:
|
||||
filled_child = _fill_schema_template_data(
|
||||
template, single_template_data
|
||||
)
|
||||
|
||||
except SchemaTemplateMissingKeys as exc:
|
||||
raise SchemaTemplateMissingKeys(
|
||||
exc.missing_keys, exc.required_keys, template_name
|
||||
)
|
||||
|
||||
for item in filled_child:
|
||||
filled_item = _fill_inner_schemas(
|
||||
item, schema_collection, schema_templates
|
||||
)
|
||||
if filled_item["type"] == "schema_template":
|
||||
output.extend(_fill_schema_template(
|
||||
filled_item, schema_collection, schema_templates
|
||||
))
|
||||
else:
|
||||
output.append(filled_item)
|
||||
return output
|
||||
|
||||
|
||||
def _fill_inner_schemas(schema_data, schema_collection, schema_templates):
|
||||
if schema_data["type"] == "schema":
|
||||
raise ValueError("First item in schema data can't be schema.")
|
||||
|
||||
children_key = "children"
|
||||
object_type_key = "object_type"
|
||||
for item_key in (children_key, object_type_key):
|
||||
children = schema_data.get(item_key)
|
||||
if not children:
|
||||
continue
|
||||
|
||||
if object_type_key == item_key:
|
||||
if not isinstance(children, dict):
|
||||
continue
|
||||
children = [children]
|
||||
|
||||
new_children = []
|
||||
for child in children:
|
||||
child_type = child["type"]
|
||||
if child_type == "schema":
|
||||
schema_name = child["name"]
|
||||
if schema_name not in schema_collection:
|
||||
if schema_name in schema_templates:
|
||||
raise KeyError((
|
||||
"Schema template \"{}\" is used as `schema`"
|
||||
).format(schema_name))
|
||||
raise KeyError(
|
||||
"Schema \"{}\" was not found".format(schema_name)
|
||||
)
|
||||
|
||||
filled_child = _fill_inner_schemas(
|
||||
schema_collection[schema_name],
|
||||
schema_collection,
|
||||
schema_templates
|
||||
)
|
||||
|
||||
elif child_type == "schema_template":
|
||||
for filled_child in _fill_schema_template(
|
||||
child, schema_collection, schema_templates
|
||||
):
|
||||
new_children.append(filled_child)
|
||||
continue
|
||||
|
||||
else:
|
||||
filled_child = _fill_inner_schemas(
|
||||
child, schema_collection, schema_templates
|
||||
)
|
||||
|
||||
new_children.append(filled_child)
|
||||
|
||||
if item_key == object_type_key:
|
||||
if len(new_children) != 1:
|
||||
raise KeyError((
|
||||
"Failed to fill object type with type: {} | name {}"
|
||||
).format(
|
||||
child_type, str(child.get("name"))
|
||||
))
|
||||
new_children = new_children[0]
|
||||
|
||||
schema_data[item_key] = new_children
|
||||
return schema_data
|
||||
|
||||
|
||||
# TODO reimplement logic inside entities
|
||||
def validate_environment_groups_uniquenes(
|
||||
schema_data, env_groups=None, keys=None
|
||||
):
|
||||
is_first = False
|
||||
if env_groups is None:
|
||||
is_first = True
|
||||
env_groups = {}
|
||||
keys = []
|
||||
|
||||
my_keys = copy.deepcopy(keys)
|
||||
key = schema_data.get("key")
|
||||
if key:
|
||||
my_keys.append(key)
|
||||
|
||||
env_group_key = schema_data.get("env_group_key")
|
||||
if env_group_key:
|
||||
if env_group_key not in env_groups:
|
||||
env_groups[env_group_key] = []
|
||||
env_groups[env_group_key].append("/".join(my_keys))
|
||||
|
||||
children = schema_data.get("children")
|
||||
if not children:
|
||||
return
|
||||
|
||||
for child in children:
|
||||
validate_environment_groups_uniquenes(
|
||||
child, env_groups, copy.deepcopy(my_keys)
|
||||
)
|
||||
|
||||
if is_first:
|
||||
invalid = {}
|
||||
for env_group_key, key_paths in env_groups.items():
|
||||
if len(key_paths) > 1:
|
||||
invalid[env_group_key] = key_paths
|
||||
|
||||
if invalid:
|
||||
raise SchemaDuplicatedEnvGroupKeys(invalid)
|
||||
|
||||
|
||||
def validate_schema(schema_data):
|
||||
validate_environment_groups_uniquenes(schema_data)
|
||||
|
||||
|
||||
def get_gui_schema(subfolder, main_schema_name):
|
||||
dirpath = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"schemas",
|
||||
subfolder
|
||||
)
|
||||
loaded_schemas = {}
|
||||
loaded_schema_templates = {}
|
||||
for root, _, filenames in os.walk(dirpath):
|
||||
for filename in filenames:
|
||||
basename, ext = os.path.splitext(filename)
|
||||
if ext != ".json":
|
||||
continue
|
||||
|
||||
filepath = os.path.join(root, filename)
|
||||
with open(filepath, "r") as json_stream:
|
||||
try:
|
||||
schema_data = json.load(json_stream)
|
||||
except Exception as exc:
|
||||
raise ValueError((
|
||||
"Unable to parse JSON file {}\n{}"
|
||||
).format(filepath, str(exc)))
|
||||
if isinstance(schema_data, list):
|
||||
loaded_schema_templates[basename] = schema_data
|
||||
else:
|
||||
loaded_schemas[basename] = schema_data
|
||||
|
||||
main_schema = _fill_inner_schemas(
|
||||
loaded_schemas[main_schema_name],
|
||||
loaded_schemas,
|
||||
loaded_schema_templates
|
||||
)
|
||||
validate_schema(main_schema)
|
||||
return main_schema
|
||||
|
||||
|
||||
def get_studio_settings_schema():
|
||||
return get_gui_schema("system_schema", "schema_main")
|
||||
|
||||
|
||||
def get_project_settings_schema():
|
||||
return get_gui_schema("projects_schema", "schema_main")
|
||||
|
||||
|
||||
class OverrideStateItem:
|
||||
"""Object used as item for `OverrideState` enum.
|
||||
|
||||
Used object to be able use exact object comparison and value comparisons.
|
||||
"""
|
||||
values = set()
|
||||
|
||||
def __init__(self, value, name):
|
||||
self.name = name
|
||||
if value in self.__class__.values:
|
||||
raise ValueError(
|
||||
"Implementation bug: Override State with same value as other."
|
||||
)
|
||||
self.__class__.values.add(value)
|
||||
self.value = value
|
||||
|
||||
def __repr__(self):
|
||||
return "<object {}> {} {}".format(
|
||||
self.__class__.__name__, self.value, self.name
|
||||
)
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Defines behavior for the equality operator, ==."""
|
||||
if isinstance(other, OverrideStateItem):
|
||||
return self.value == other.value
|
||||
return self.value == other
|
||||
|
||||
def __gt__(self, other):
|
||||
"""Defines behavior for the greater-than operator, >."""
|
||||
if isinstance(other, OverrideStateItem):
|
||||
return self.value > other.value
|
||||
return self.value > other
|
||||
|
||||
def __lt__(self, other):
|
||||
"""Defines behavior for the less-than operator, <."""
|
||||
if isinstance(other, OverrideStateItem):
|
||||
return self.value < other.value
|
||||
return self.value < other
|
||||
|
||||
def __le__(self, other):
|
||||
"""Defines behavior for the less-than-or-equal-to operator, <=."""
|
||||
if isinstance(other, OverrideStateItem):
|
||||
return self.value == other.value or self.value < other.value
|
||||
return self.value == other or self.value < other
|
||||
|
||||
def __ge__(self, other):
|
||||
"""Defines behavior for the greater-than-or-equal-to operator, >=."""
|
||||
if isinstance(other, OverrideStateItem):
|
||||
return self.value == other.value or self.value > other.value
|
||||
return self.value == other or self.value > other
|
||||
|
||||
|
||||
class OverrideState:
|
||||
"""Enumeration of override states.
|
||||
|
||||
Each state have unique value.
|
||||
|
||||
Currently has 4 states:
|
||||
- NOT_DEFINED - Initial state will raise an error if want to access
|
||||
anything in entity.
|
||||
- DEFAULTS - Entity cares only about default values. It is not
|
||||
possible to set higher state if any entity does not have filled
|
||||
default value.
|
||||
- STUDIO - First layer of overrides. Hold only studio overriden values
|
||||
that are applied on top of defaults.
|
||||
- PROJECT - Second layer of overrides. Hold only project overrides that are
|
||||
applied on top of defaults and studio overrides.
|
||||
"""
|
||||
NOT_DEFINED = OverrideStateItem(-1, "Not defined")
|
||||
DEFAULTS = OverrideStateItem(0, "Defaults")
|
||||
STUDIO = OverrideStateItem(1, "Studio overrides")
|
||||
PROJECT = OverrideStateItem(2, "Project Overrides")
|
||||
470
openpype/settings/entities/list_entity.py
Normal file
470
openpype/settings/entities/list_entity.py
Normal file
|
|
@ -0,0 +1,470 @@
|
|||
import copy
|
||||
from . import (
|
||||
BaseEntity,
|
||||
EndpointEntity
|
||||
)
|
||||
from .lib import (
|
||||
NOT_SET,
|
||||
OverrideState
|
||||
)
|
||||
from .exceptions import (
|
||||
DefaultsNotDefined,
|
||||
StudioDefaultsNotDefined,
|
||||
EntitySchemaError
|
||||
)
|
||||
|
||||
|
||||
class ListEntity(EndpointEntity):
|
||||
schema_types = ["list"]
|
||||
_default_label_wrap = {
|
||||
"use_label_wrap": False,
|
||||
"collapsible": True,
|
||||
"collapsed": False
|
||||
}
|
||||
|
||||
def __iter__(self):
|
||||
for item in self.children:
|
||||
yield item
|
||||
|
||||
def __bool__(self):
|
||||
"""Returns true because len may return 0."""
|
||||
return True
|
||||
|
||||
def __len__(self):
|
||||
return len(self.children)
|
||||
|
||||
def __contains__(self, item):
|
||||
if isinstance(item, BaseEntity):
|
||||
for child_entity in self.children:
|
||||
if child_entity.id == item.id:
|
||||
return True
|
||||
return False
|
||||
|
||||
for _item in self.value:
|
||||
if item == _item:
|
||||
return True
|
||||
return False
|
||||
|
||||
def index(self, item):
|
||||
if isinstance(item, BaseEntity):
|
||||
for idx, child_entity in enumerate(self.children):
|
||||
if child_entity.id == item.id:
|
||||
return idx
|
||||
else:
|
||||
for idx, _item in enumerate(self.value):
|
||||
if item == _item:
|
||||
return idx
|
||||
raise ValueError(
|
||||
"{} is not in {}".format(item, self.__class__.__name__)
|
||||
)
|
||||
|
||||
def append(self, item):
|
||||
child_obj = self._add_new_item()
|
||||
child_obj.set_override_state(self._override_state)
|
||||
child_obj.set(item)
|
||||
self.on_change()
|
||||
|
||||
def extend(self, items):
|
||||
for item in items:
|
||||
self.append(item)
|
||||
|
||||
def clear(self):
|
||||
self.children.clear()
|
||||
self.on_change()
|
||||
|
||||
def pop(self, idx):
|
||||
item = self.children.pop(idx)
|
||||
self.on_change()
|
||||
return item
|
||||
|
||||
def remove(self, item):
|
||||
for idx, child_obj in enumerate(self.children):
|
||||
found = False
|
||||
if isinstance(item, BaseEntity):
|
||||
if child_obj is item:
|
||||
found = True
|
||||
elif child_obj.value == item:
|
||||
found = True
|
||||
|
||||
if found:
|
||||
self.pop(idx)
|
||||
return
|
||||
raise ValueError("ListEntity.remove(x): x not in ListEntity")
|
||||
|
||||
def insert(self, idx, item):
|
||||
child_obj = self._add_new_item(idx)
|
||||
child_obj.set_override_state(self._override_state)
|
||||
child_obj.set(item)
|
||||
self.on_change()
|
||||
|
||||
def _add_new_item(self, idx=None):
|
||||
child_obj = self.create_schema_object(self.item_schema, self, True)
|
||||
if idx is None:
|
||||
self.children.append(child_obj)
|
||||
else:
|
||||
self.children.insert(idx, child_obj)
|
||||
return child_obj
|
||||
|
||||
def add_new_item(self, idx=None):
|
||||
child_obj = self._add_new_item(idx)
|
||||
child_obj.set_override_state(self._override_state)
|
||||
self.on_change()
|
||||
return child_obj
|
||||
|
||||
def swap_items(self, item_1, item_2):
|
||||
index_1 = self.index(item_1)
|
||||
index_2 = self.index(item_2)
|
||||
self.swap_indexes(index_1, index_2)
|
||||
|
||||
def swap_indexes(self, index_1, index_2):
|
||||
children_len = len(self.children)
|
||||
if index_1 > children_len or index_2 > children_len:
|
||||
raise IndexError(
|
||||
"{} index out of range".format(self.__class__.__name__)
|
||||
)
|
||||
self.children[index_1], self.children[index_2] = (
|
||||
self.children[index_2], self.children[index_1]
|
||||
)
|
||||
self.on_change()
|
||||
|
||||
def _convert_to_valid_type(self, value):
|
||||
if isinstance(value, (set, tuple)):
|
||||
return list(value)
|
||||
return NOT_SET
|
||||
|
||||
def _item_initalization(self):
|
||||
self.valid_value_types = (list, )
|
||||
self.children = []
|
||||
self.value_on_not_set = []
|
||||
|
||||
self._ignore_child_changes = False
|
||||
|
||||
item_schema = self.schema_data["object_type"]
|
||||
if not isinstance(item_schema, dict):
|
||||
item_schema = {"type": item_schema}
|
||||
self.item_schema = item_schema
|
||||
|
||||
if not self.group_item:
|
||||
self.is_group = True
|
||||
|
||||
# Value that was set on set_override_state
|
||||
self.initial_value = []
|
||||
|
||||
def schema_validations(self):
|
||||
super(ListEntity, self).schema_validations()
|
||||
|
||||
if self.is_dynamic_item and self.use_label_wrap:
|
||||
reason = (
|
||||
"`ListWidget` can't have set `use_label_wrap` to True and"
|
||||
" be used as widget at the same time."
|
||||
)
|
||||
raise EntitySchemaError(self, reason)
|
||||
|
||||
if self.use_label_wrap and not self.label:
|
||||
reason = (
|
||||
"`ListWidget` can't have set `use_label_wrap` to True and"
|
||||
" not have set \"label\" key at the same time."
|
||||
)
|
||||
raise EntitySchemaError(self, reason)
|
||||
|
||||
for child_obj in self.children:
|
||||
child_obj.schema_validations()
|
||||
|
||||
def get_child_path(self, child_obj):
|
||||
result_idx = None
|
||||
for idx, _child_obj in enumerate(self.children):
|
||||
if _child_obj is child_obj:
|
||||
result_idx = idx
|
||||
break
|
||||
|
||||
if result_idx is None:
|
||||
raise ValueError("Didn't found child {}".format(child_obj))
|
||||
|
||||
return "/".join([self.path, str(result_idx)])
|
||||
|
||||
def set(self, value):
|
||||
new_value = self.convert_to_valid_type(value)
|
||||
self.clear()
|
||||
for item in new_value:
|
||||
self.append(item)
|
||||
|
||||
def on_child_change(self, _child_entity):
|
||||
if self._ignore_child_changes:
|
||||
return
|
||||
|
||||
if self._override_state is OverrideState.STUDIO:
|
||||
self._has_studio_override = True
|
||||
elif self._override_state is OverrideState.PROJECT:
|
||||
self._has_project_override = True
|
||||
self.on_change()
|
||||
|
||||
def set_override_state(self, state):
|
||||
# Trigger override state change of root if is not same
|
||||
if self.root_item.override_state is not state:
|
||||
self.root_item.set_override_state(state)
|
||||
return
|
||||
|
||||
self._override_state = state
|
||||
|
||||
while self.children:
|
||||
self.children.pop(0)
|
||||
|
||||
# Ignore if is dynamic item and use default in that case
|
||||
if not self.is_dynamic_item and not self.is_in_dynamic_item:
|
||||
if state > OverrideState.DEFAULTS:
|
||||
if not self.has_default_value:
|
||||
raise DefaultsNotDefined(self)
|
||||
|
||||
elif state > OverrideState.STUDIO:
|
||||
if not self.had_studio_override:
|
||||
raise StudioDefaultsNotDefined(self)
|
||||
|
||||
value = NOT_SET
|
||||
if self._override_state is OverrideState.PROJECT:
|
||||
if self.had_project_override:
|
||||
value = self._project_override_value
|
||||
self._has_project_override = self.had_project_override
|
||||
|
||||
if value is NOT_SET or self._override_state is OverrideState.STUDIO:
|
||||
if self.had_studio_override:
|
||||
value = self._studio_override_value
|
||||
self._has_studio_override = self.had_studio_override
|
||||
|
||||
if value is NOT_SET or self._override_state is OverrideState.DEFAULTS:
|
||||
if self.has_default_value:
|
||||
value = self._default_value
|
||||
else:
|
||||
value = self.value_on_not_set
|
||||
|
||||
for item in value:
|
||||
child_obj = self._add_new_item()
|
||||
child_obj.update_default_value(item)
|
||||
if self._override_state is OverrideState.PROJECT:
|
||||
if self.had_project_override:
|
||||
child_obj.update_project_value(item)
|
||||
elif self.had_studio_override:
|
||||
child_obj.update_studio_value(item)
|
||||
|
||||
elif self._override_state is OverrideState.STUDIO:
|
||||
if self.had_studio_override:
|
||||
child_obj.update_studio_value(item)
|
||||
|
||||
for child_obj in self.children:
|
||||
child_obj.set_override_state(self._override_state)
|
||||
|
||||
self.initial_value = self.settings_value()
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
output = []
|
||||
for child_obj in self.children:
|
||||
output.append(child_obj.value)
|
||||
return output
|
||||
|
||||
@property
|
||||
def has_unsaved_changes(self):
|
||||
if self._override_state is OverrideState.NOT_DEFINED:
|
||||
return False
|
||||
|
||||
if self._override_state is OverrideState.DEFAULTS:
|
||||
if not self.has_default_value:
|
||||
return True
|
||||
|
||||
elif self._override_state is OverrideState.STUDIO:
|
||||
if self.had_studio_override != self._has_studio_override:
|
||||
return True
|
||||
|
||||
if not self._has_studio_override and not self.has_default_value:
|
||||
return True
|
||||
|
||||
elif self._override_state is OverrideState.PROJECT:
|
||||
if self.had_project_override != self._has_project_override:
|
||||
return True
|
||||
|
||||
if (
|
||||
not self._has_project_override
|
||||
and not self._has_studio_override
|
||||
and not self.has_default_value
|
||||
):
|
||||
return True
|
||||
|
||||
if self._child_has_unsaved_changes:
|
||||
return True
|
||||
|
||||
if self.settings_value() != self.initial_value:
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def has_studio_override(self):
|
||||
if self._override_state >= OverrideState.STUDIO:
|
||||
return (
|
||||
self._has_studio_override
|
||||
or self._child_has_studio_override
|
||||
)
|
||||
return False
|
||||
|
||||
@property
|
||||
def has_project_override(self):
|
||||
if self._override_state >= OverrideState.PROJECT:
|
||||
return (
|
||||
self._has_project_override
|
||||
or self._child_has_project_override
|
||||
)
|
||||
return False
|
||||
|
||||
@property
|
||||
def _child_has_unsaved_changes(self):
|
||||
for child_obj in self.children:
|
||||
if child_obj.has_unsaved_changes:
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def _child_has_studio_override(self):
|
||||
if self._override_state >= OverrideState.STUDIO:
|
||||
for child_obj in self.children:
|
||||
if child_obj.has_studio_override:
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def _child_has_project_override(self):
|
||||
if self._override_state is OverrideState.PROJECT:
|
||||
for child_obj in self.children:
|
||||
if child_obj.has_project_override:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _settings_value(self):
|
||||
output = []
|
||||
for child_obj in self.children:
|
||||
output.append(child_obj.settings_value())
|
||||
return output
|
||||
|
||||
def _discard_changes(self, on_change_trigger):
|
||||
if self._override_state is OverrideState.NOT_DEFINED:
|
||||
return
|
||||
|
||||
not_set = object()
|
||||
value = not_set
|
||||
if (
|
||||
self._override_state >= OverrideState.PROJECT
|
||||
and self.had_project_override
|
||||
):
|
||||
value = copy.deepcopy(self._project_override_value)
|
||||
|
||||
if (
|
||||
value is not_set
|
||||
and self._override_state >= OverrideState.STUDIO
|
||||
and self.had_studio_override
|
||||
):
|
||||
value = copy.deepcopy(self._studio_override_value)
|
||||
|
||||
if value is not_set and self._override_state >= OverrideState.DEFAULTS:
|
||||
if self.has_default_value:
|
||||
value = copy.deepcopy(self._default_value)
|
||||
else:
|
||||
value = copy.deepcopy(self.value_on_not_set)
|
||||
|
||||
if value is not_set:
|
||||
raise NotImplementedError("BUG: Unexcpected part of code.")
|
||||
|
||||
self._ignore_child_changes = True
|
||||
|
||||
while self.children:
|
||||
self.children.pop(0)
|
||||
|
||||
for item in value:
|
||||
child_obj = self._add_new_item()
|
||||
child_obj.update_default_value(item)
|
||||
if self._override_state is OverrideState.PROJECT:
|
||||
if self.had_project_override:
|
||||
child_obj.update_project_value(item)
|
||||
elif self.had_studio_override:
|
||||
child_obj.update_studio_value(item)
|
||||
|
||||
elif self._override_state is OverrideState.STUDIO:
|
||||
if self.had_studio_override:
|
||||
child_obj.update_studio_value(item)
|
||||
|
||||
child_obj.set_override_state(self._override_state)
|
||||
|
||||
if self._override_state >= OverrideState.PROJECT:
|
||||
self._has_project_override = self.had_project_override
|
||||
|
||||
if self._override_state >= OverrideState.STUDIO:
|
||||
self._has_studio_override = self.had_studio_override
|
||||
|
||||
self._ignore_child_changes = False
|
||||
|
||||
on_change_trigger.append(self.on_change)
|
||||
|
||||
def _add_to_studio_default(self, _on_change_trigger):
|
||||
self._has_studio_override = True
|
||||
self.on_change()
|
||||
|
||||
def _remove_from_studio_default(self, on_change_trigger):
|
||||
if self._override_state is not OverrideState.STUDIO:
|
||||
return
|
||||
|
||||
value = self._default_value
|
||||
if value is NOT_SET:
|
||||
value = self.value_on_not_set
|
||||
|
||||
self._ignore_child_changes = True
|
||||
|
||||
while self.children:
|
||||
self.children.pop(0)
|
||||
|
||||
for item in value:
|
||||
child_obj = self._add_new_item()
|
||||
child_obj.update_default_value(item)
|
||||
child_obj.set_override_state(self._override_state)
|
||||
|
||||
self._ignore_child_changes = False
|
||||
|
||||
self._has_studio_override = False
|
||||
|
||||
on_change_trigger.append(self.on_change)
|
||||
|
||||
def _add_to_project_override(self, _on_change_trigger):
|
||||
self._has_project_override = True
|
||||
self.on_change()
|
||||
|
||||
def _remove_from_project_override(self, on_change_trigger):
|
||||
if self._override_state is not OverrideState.PROJECT:
|
||||
return
|
||||
|
||||
if not self.has_project_override:
|
||||
return
|
||||
|
||||
if self._has_studio_override:
|
||||
value = self._studio_override_value
|
||||
elif self.has_default_value:
|
||||
value = self._default_value
|
||||
else:
|
||||
value = self.value_on_not_set
|
||||
|
||||
self._ignore_child_changes = True
|
||||
|
||||
while self.children:
|
||||
self.children.pop(0)
|
||||
|
||||
for item in value:
|
||||
child_obj = self._add_new_item()
|
||||
child_obj.update_default_value(item)
|
||||
if self._has_studio_override:
|
||||
child_obj.update_studio_value(item)
|
||||
child_obj.set_override_state(self._override_state)
|
||||
|
||||
self._ignore_child_changes = False
|
||||
|
||||
self._has_project_override = False
|
||||
|
||||
on_change_trigger.append(self.on_change)
|
||||
|
||||
def reset_callbacks(self):
|
||||
super(ListEntity, self).reset_callbacks()
|
||||
for child_entity in self.children:
|
||||
child_entity.reset_callbacks()
|
||||
739
openpype/settings/entities/root_entities.py
Normal file
739
openpype/settings/entities/root_entities.py
Normal file
|
|
@ -0,0 +1,739 @@
|
|||
import os
|
||||
import json
|
||||
import copy
|
||||
import inspect
|
||||
|
||||
from abc import abstractmethod
|
||||
|
||||
from .base_entity import BaseItemEntity
|
||||
from .lib import (
|
||||
NOT_SET,
|
||||
WRAPPER_TYPES,
|
||||
OverrideState,
|
||||
get_studio_settings_schema,
|
||||
get_project_settings_schema
|
||||
)
|
||||
from .exceptions import (
|
||||
SchemaError,
|
||||
InvalidKeySymbols
|
||||
)
|
||||
from openpype.settings.constants import (
|
||||
SYSTEM_SETTINGS_KEY,
|
||||
PROJECT_SETTINGS_KEY,
|
||||
PROJECT_ANATOMY_KEY,
|
||||
KEY_REGEX
|
||||
)
|
||||
|
||||
from openpype.settings.lib import (
|
||||
DEFAULTS_DIR,
|
||||
|
||||
get_default_settings,
|
||||
|
||||
get_studio_system_settings_overrides,
|
||||
save_studio_settings,
|
||||
|
||||
get_studio_project_settings_overrides,
|
||||
get_studio_project_anatomy_overrides,
|
||||
get_project_settings_overrides,
|
||||
get_project_anatomy_overrides,
|
||||
save_project_settings,
|
||||
save_project_anatomy,
|
||||
|
||||
find_environments,
|
||||
apply_overrides
|
||||
)
|
||||
|
||||
|
||||
class RootEntity(BaseItemEntity):
|
||||
"""Abstract class for root entities.
|
||||
|
||||
Root entity is top hierarchy entity without parent. Should care about
|
||||
saving and must have access to all entities in it's scope.
|
||||
"""
|
||||
schema_types = ["root"]
|
||||
|
||||
def __init__(self, schema_data, reset):
|
||||
super(RootEntity, self).__init__(schema_data)
|
||||
self._item_initalization()
|
||||
if reset:
|
||||
self.reset()
|
||||
|
||||
@property
|
||||
def override_state(self):
|
||||
"""Current OverrideState."""
|
||||
return self._override_state
|
||||
|
||||
@abstractmethod
|
||||
def reset(self):
|
||||
"""Reset values and entities to initial state.
|
||||
|
||||
Reload settings and entities should reset their changes or be
|
||||
recreated.
|
||||
"""
|
||||
pass
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.non_gui_children[key]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self.non_gui_children[key].set(value)
|
||||
|
||||
def __iter__(self):
|
||||
for key in self.keys():
|
||||
yield key
|
||||
|
||||
def get(self, key, default=None):
|
||||
return self.non_gui_children.get(key, default)
|
||||
|
||||
def set(self, value):
|
||||
"""Set value."""
|
||||
new_value = self.convert_to_valid_type(value)
|
||||
for _key, _value in new_value.items():
|
||||
self.non_gui_children[_key].set(_value)
|
||||
|
||||
def keys(self):
|
||||
return self.non_gui_children.keys()
|
||||
|
||||
def values(self):
|
||||
return self.non_gui_children.values()
|
||||
|
||||
def items(self):
|
||||
return self.non_gui_children.items()
|
||||
|
||||
def _add_children(self, schema_data, first=True):
|
||||
added_children = []
|
||||
for children_schema in schema_data["children"]:
|
||||
if children_schema["type"] in WRAPPER_TYPES:
|
||||
_children_schema = copy.deepcopy(children_schema)
|
||||
wrapper_children = self._add_children(
|
||||
children_schema["children"], False
|
||||
)
|
||||
_children_schema["children"] = wrapper_children
|
||||
added_children.append(_children_schema)
|
||||
continue
|
||||
|
||||
child_obj = self.create_schema_object(children_schema, self)
|
||||
self.children.append(child_obj)
|
||||
added_children.append(child_obj)
|
||||
if isinstance(child_obj, self._gui_types):
|
||||
continue
|
||||
|
||||
if child_obj.key in self.non_gui_children:
|
||||
raise KeyError("Duplicated key \"{}\"".format(child_obj.key))
|
||||
self.non_gui_children[child_obj.key] = child_obj
|
||||
|
||||
if not first:
|
||||
return added_children
|
||||
|
||||
for child_obj in added_children:
|
||||
self.gui_layout.append(child_obj)
|
||||
|
||||
def _item_initalization(self):
|
||||
# Store `self` to `root_item` for children entities
|
||||
self.root_item = self
|
||||
|
||||
self._loaded_types = None
|
||||
self._gui_types = None
|
||||
|
||||
# Children are stored by key as keys are immutable and are defined by
|
||||
# schema
|
||||
self.valid_value_types = (dict, )
|
||||
|
||||
self.children = []
|
||||
self.non_gui_children = {}
|
||||
self.gui_layout = []
|
||||
|
||||
self._add_children(self.schema_data)
|
||||
|
||||
self.schema_validations()
|
||||
|
||||
def schema_validations(self):
|
||||
for child_entity in self.children:
|
||||
if child_entity.is_group:
|
||||
reason = (
|
||||
"Root entity \"{}\" has child with `is_group`"
|
||||
" attribute set to True but root can't save overrides."
|
||||
).format(self.__class__.__name__)
|
||||
raise SchemaError(reason)
|
||||
child_entity.schema_validations()
|
||||
|
||||
for key in self.non_gui_children.keys():
|
||||
if not KEY_REGEX.match(key):
|
||||
raise InvalidKeySymbols(self.path, key)
|
||||
|
||||
def get_entity_from_path(self, path):
|
||||
"""Return system settings entity."""
|
||||
raise NotImplementedError((
|
||||
"Method `get_entity_from_path` not available for \"{}\""
|
||||
).format(self.__class__.__name__))
|
||||
|
||||
def create_schema_object(self, schema_data, *args, **kwargs):
|
||||
"""Create entity by entered schema data.
|
||||
|
||||
Available entities are loaded on first run. Children entities can call
|
||||
this method.
|
||||
"""
|
||||
if self._loaded_types is None:
|
||||
# Load available entities
|
||||
from openpype.settings import entities
|
||||
|
||||
# Define known abstract classes
|
||||
known_abstract_classes = (
|
||||
entities.BaseEntity,
|
||||
entities.BaseItemEntity,
|
||||
entities.ItemEntity,
|
||||
entities.EndpointEntity,
|
||||
entities.InputEntity,
|
||||
entities.BaseEnumEntity
|
||||
)
|
||||
|
||||
self._loaded_types = {}
|
||||
_gui_types = []
|
||||
for attr in dir(entities):
|
||||
item = getattr(entities, attr)
|
||||
# Filter classes
|
||||
if not inspect.isclass(item):
|
||||
continue
|
||||
|
||||
# Skip classes that do not inherit from BaseEntity
|
||||
if not issubclass(item, entities.BaseEntity):
|
||||
continue
|
||||
|
||||
# Skip class that is abstract by design
|
||||
if item in known_abstract_classes:
|
||||
continue
|
||||
|
||||
if inspect.isabstract(item):
|
||||
# Create an object to get crash and get traceback
|
||||
item()
|
||||
|
||||
# Backwards compatibility
|
||||
# Single entity may have multiple schema types
|
||||
for schema_type in item.schema_types:
|
||||
self._loaded_types[schema_type] = item
|
||||
|
||||
if item.gui_type:
|
||||
_gui_types.append(item)
|
||||
self._gui_types = tuple(_gui_types)
|
||||
|
||||
klass = self._loaded_types.get(schema_data["type"])
|
||||
if not klass:
|
||||
raise KeyError("Unknown type \"{}\"".format(schema_data["type"]))
|
||||
|
||||
return klass(schema_data, *args, **kwargs)
|
||||
|
||||
def set_override_state(self, state):
|
||||
"""Set override state and trigger it on children.
|
||||
|
||||
Method will discard all changes in hierarchy and use values, metadata
|
||||
and all kind of values for defined state.
|
||||
|
||||
Args:
|
||||
state (OverrideState): State to which should be data changed.
|
||||
"""
|
||||
self._override_state = state
|
||||
for child_obj in self.non_gui_children.values():
|
||||
child_obj.set_override_state(state)
|
||||
|
||||
def on_change(self):
|
||||
"""Trigger callbacks on change."""
|
||||
for callback in self.on_change_callbacks:
|
||||
callback()
|
||||
|
||||
def on_child_change(self, _child_entity):
|
||||
"""Whan any children has changed."""
|
||||
self.on_change()
|
||||
|
||||
def get_child_path(self, child_entity):
|
||||
"""Return path of children entity"""
|
||||
for key, _child_entity in self.non_gui_children.items():
|
||||
if _child_entity is child_entity:
|
||||
return key
|
||||
raise ValueError("Didn't found child {}".format(child_entity))
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
"""Value for current override state without metadata."""
|
||||
output = {}
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
output[key] = child_obj.value
|
||||
return output
|
||||
|
||||
def settings_value(self):
|
||||
"""Value for current override state with metadata.
|
||||
|
||||
This is what should be stored on save method.
|
||||
"""
|
||||
if self._override_state is OverrideState.NOT_DEFINED:
|
||||
return NOT_SET
|
||||
|
||||
if self._override_state is not OverrideState.DEFAULTS:
|
||||
output = {}
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
value = child_obj.settings_value()
|
||||
if value is not NOT_SET:
|
||||
output[key] = value
|
||||
return output
|
||||
|
||||
output = {}
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
child_value = child_obj.settings_value()
|
||||
if not child_obj.is_file and not child_obj.file_item:
|
||||
for _key, _value in child_value.items():
|
||||
new_key = "/".join([key, _key])
|
||||
output[new_key] = _value
|
||||
else:
|
||||
output[key] = child_value
|
||||
return output
|
||||
|
||||
@property
|
||||
def has_studio_override(self):
|
||||
"""Any children has studio override.
|
||||
|
||||
Return's relevant data only if override state is STUDIO or PROJECT.
|
||||
|
||||
Returns:
|
||||
bool: True if any children has studio overrides.
|
||||
"""
|
||||
if self._override_state >= OverrideState.STUDIO:
|
||||
for child_obj in self.non_gui_children.values():
|
||||
if child_obj.has_studio_override:
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def has_project_override(self):
|
||||
"""Any children has project override.
|
||||
|
||||
Return's relevant data only if override state is PROJECT.
|
||||
|
||||
Returns:
|
||||
bool: True if any children has project overrides.
|
||||
"""
|
||||
if self._override_state >= OverrideState.PROJECT:
|
||||
for child_obj in self.non_gui_children.values():
|
||||
if child_obj.has_project_override:
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def has_unsaved_changes(self):
|
||||
"""Entity contain unsaved changes.
|
||||
|
||||
Root on it's own can't have any modifications so looks only on
|
||||
children.
|
||||
|
||||
Returns:
|
||||
bool: True if has unsaved changes.
|
||||
"""
|
||||
for child_obj in self.non_gui_children.values():
|
||||
if child_obj.has_unsaved_changes:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _discard_changes(self, on_change_trigger):
|
||||
"""Implementation of abstract method only trigger children callback."""
|
||||
for child_obj in self.non_gui_children.values():
|
||||
child_obj.discard_changes(on_change_trigger)
|
||||
|
||||
def _add_to_studio_default(self, *args, **kwargs):
|
||||
"""Implementation of abstract method only trigger children callback."""
|
||||
for child_obj in self.non_gui_children.values():
|
||||
child_obj.add_to_studio_default(*args, **kwargs)
|
||||
|
||||
def _remove_from_studio_default(self, on_change_trigger):
|
||||
"""Implementation of abstract method only trigger children callback."""
|
||||
for child_obj in self.non_gui_children.values():
|
||||
child_obj.remove_from_studio_default(on_change_trigger)
|
||||
|
||||
def _add_to_project_override(self, *args, **kwargs):
|
||||
"""Implementation of abstract method only trigger children callback."""
|
||||
for child_obj in self.non_gui_children.values():
|
||||
child_obj.add_to_project_override(*args, **kwargs)
|
||||
|
||||
def _remove_from_project_override(self, on_change_trigger):
|
||||
"""Implementation of abstract method only trigger children callback."""
|
||||
for child_obj in self.non_gui_children.values():
|
||||
child_obj.remove_from_project_override(on_change_trigger)
|
||||
|
||||
def save(self):
|
||||
"""Save values for current override state.
|
||||
|
||||
Values are stored with current values and modifications.
|
||||
"""
|
||||
if self._override_state is OverrideState.NOT_DEFINED:
|
||||
raise ValueError(
|
||||
"Can't save if override state is set to NOT_DEFINED"
|
||||
)
|
||||
|
||||
if self._override_state is OverrideState.DEFAULTS:
|
||||
self._save_default_values()
|
||||
|
||||
elif self._override_state is OverrideState.STUDIO:
|
||||
self._save_studio_values()
|
||||
|
||||
elif self._override_state is OverrideState.PROJECT:
|
||||
self._save_project_values()
|
||||
|
||||
# Trigger reset to reload entities
|
||||
self.reset()
|
||||
|
||||
@abstractmethod
|
||||
def defaults_dir(self):
|
||||
"""Abstract method to return directory path to defaults.
|
||||
|
||||
Implementation of `_save_default_values` requires defaults dir where
|
||||
default data will be stored.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def _validate_defaults_to_save(self, value):
|
||||
"""Validate default values before save."""
|
||||
pass
|
||||
|
||||
def _save_default_values(self):
|
||||
"""Save default values.
|
||||
|
||||
Do not call this method, always use `save`. Manually called method
|
||||
won't save current values as defaults if override state is not set to
|
||||
DEFAULTS.
|
||||
"""
|
||||
settings_value = self.settings_value()
|
||||
self._validate_defaults_to_save(settings_value)
|
||||
|
||||
defaults_dir = self.defaults_dir()
|
||||
for file_path, value in settings_value.items():
|
||||
subpath = file_path + ".json"
|
||||
|
||||
output_path = os.path.join(defaults_dir, subpath)
|
||||
dirpath = os.path.dirname(output_path)
|
||||
if not os.path.exists(dirpath):
|
||||
os.makedirs(dirpath)
|
||||
|
||||
self.log.debug("Saving data to: {}\n{}".format(subpath, value))
|
||||
with open(output_path, "w") as file_stream:
|
||||
json.dump(value, file_stream, indent=4)
|
||||
|
||||
@abstractmethod
|
||||
def _save_studio_values(self):
|
||||
"""Save studio override values."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def _save_project_values(self):
|
||||
"""Save project override values."""
|
||||
pass
|
||||
|
||||
def is_in_defaults_state(self):
|
||||
"""Api callback to check if current state is DEFAULTS."""
|
||||
return self._override_state is OverrideState.DEFAULTS
|
||||
|
||||
def is_in_studio_state(self):
|
||||
"""Api callback to check if current state is STUDIO."""
|
||||
return self._override_state is OverrideState.STUDIO
|
||||
|
||||
def is_in_project_state(self):
|
||||
"""Api callback to check if current state is PROJECT."""
|
||||
return self._override_state is OverrideState.PROJECT
|
||||
|
||||
def set_defaults_state(self):
|
||||
"""Change override state to DEFAULTS."""
|
||||
self.set_override_state(OverrideState.DEFAULTS)
|
||||
|
||||
def set_studio_state(self):
|
||||
"""Change override state to STUDIO."""
|
||||
self.set_override_state(OverrideState.STUDIO)
|
||||
|
||||
def set_project_state(self):
|
||||
"""Change override state to PROJECT."""
|
||||
self.set_override_state(OverrideState.PROJECT)
|
||||
|
||||
|
||||
class SystemSettings(RootEntity):
|
||||
"""Root entity for system settings.
|
||||
|
||||
Allows to modify system settings via entity system and loaded schemas.
|
||||
|
||||
Args:
|
||||
set_studio_state (bool): Set studio values on initialization. By
|
||||
default is set to True.
|
||||
reset (bool): Reset values on initialization. By default is set to
|
||||
True.
|
||||
schema_data (dict): Pass schema data to entity. This is for development
|
||||
and debugging purposes.
|
||||
"""
|
||||
def __init__(
|
||||
self, set_studio_state=True, reset=True, schema_data=None
|
||||
):
|
||||
if schema_data is None:
|
||||
# Load system schemas
|
||||
schema_data = get_studio_settings_schema()
|
||||
|
||||
super(SystemSettings, self).__init__(schema_data, reset)
|
||||
|
||||
if set_studio_state:
|
||||
self.set_studio_state()
|
||||
|
||||
def _reset_values(self):
|
||||
default_value = get_default_settings()[SYSTEM_SETTINGS_KEY]
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
value = default_value.get(key, NOT_SET)
|
||||
child_obj.update_default_value(value)
|
||||
|
||||
studio_overrides = get_studio_system_settings_overrides()
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
value = studio_overrides.get(key, NOT_SET)
|
||||
child_obj.update_studio_value(value)
|
||||
|
||||
def reset(self, new_state=None):
|
||||
"""Discard changes and reset entit's values.
|
||||
|
||||
Reload default values and studio override values and update entities.
|
||||
|
||||
Args:
|
||||
new_state (OverrideState): It is possible to change override state
|
||||
during reset. Current state is used if not defined.
|
||||
"""
|
||||
if new_state is None:
|
||||
new_state = self._override_state
|
||||
|
||||
if new_state is OverrideState.NOT_DEFINED:
|
||||
new_state = OverrideState.DEFAULTS
|
||||
|
||||
if new_state is OverrideState.PROJECT:
|
||||
raise ValueError("System settings can't store poject overrides.")
|
||||
|
||||
self._reset_values()
|
||||
self.set_override_state(new_state)
|
||||
|
||||
def defaults_dir(self):
|
||||
"""Path to defaults directory.
|
||||
|
||||
Implementation of abstract method.
|
||||
"""
|
||||
return os.path.join(DEFAULTS_DIR, SYSTEM_SETTINGS_KEY)
|
||||
|
||||
def _save_studio_values(self):
|
||||
settings_value = self.settings_value()
|
||||
|
||||
self._validate_duplicated_env_group(settings_value)
|
||||
|
||||
self.log.debug("Saving system settings: {}".format(
|
||||
json.dumps(settings_value, indent=4)
|
||||
))
|
||||
save_studio_settings(settings_value)
|
||||
|
||||
def _validate_defaults_to_save(self, value):
|
||||
"""Valiations of default values before save."""
|
||||
self._validate_duplicated_env_group(value)
|
||||
|
||||
def _validate_duplicated_env_group(self, value, override_state=None):
|
||||
""" Validate duplicated environment groups.
|
||||
|
||||
Raises:
|
||||
DuplicatedEnvGroups: When value contain duplicated env groups.
|
||||
"""
|
||||
value = copy.deepcopy(value)
|
||||
if override_state is None:
|
||||
override_state = self._override_state
|
||||
|
||||
if override_state is OverrideState.STUDIO:
|
||||
default_values = get_default_settings()[SYSTEM_SETTINGS_KEY]
|
||||
final_value = apply_overrides(default_values, value)
|
||||
else:
|
||||
final_value = value
|
||||
|
||||
# Check if final_value contain duplicated environment groups
|
||||
find_environments(final_value)
|
||||
|
||||
def _save_project_values(self):
|
||||
"""System settings can't have project overrides.
|
||||
|
||||
Raises:
|
||||
ValueError: Raise when called as entity can't use or store project
|
||||
overrides.
|
||||
"""
|
||||
raise ValueError("System settings can't save project overrides.")
|
||||
|
||||
|
||||
class ProjectSettings(RootEntity):
|
||||
"""Root entity for project settings.
|
||||
|
||||
Allows to modify project settings via entity system and loaded schemas.
|
||||
|
||||
Args:
|
||||
project_name (str): Project name which overrides will be loaded.
|
||||
Use `None` to modify studio defaults.
|
||||
change_state (bool): Set values on initialization. By
|
||||
default is set to True.
|
||||
reset (bool): Reset values on initialization. By default is set to
|
||||
True.
|
||||
schema_data (dict): Pass schema data to entity. This is for development
|
||||
and debugging purposes.
|
||||
"""
|
||||
def __init__(
|
||||
self,
|
||||
project_name=None,
|
||||
change_state=True,
|
||||
reset=True,
|
||||
schema_data=None
|
||||
):
|
||||
self._project_name = project_name
|
||||
|
||||
self._system_settings_entity = None
|
||||
|
||||
if schema_data is None:
|
||||
# Load system schemas
|
||||
schema_data = get_project_settings_schema()
|
||||
|
||||
super(ProjectSettings, self).__init__(schema_data, reset)
|
||||
|
||||
if change_state:
|
||||
if self.project_name is None:
|
||||
self.set_studio_state()
|
||||
else:
|
||||
self.set_project_state()
|
||||
|
||||
@property
|
||||
def project_name(self):
|
||||
return self._project_name
|
||||
|
||||
@project_name.setter
|
||||
def project_name(self, project_name):
|
||||
self.change_project(project_name)
|
||||
|
||||
@property
|
||||
def system_settings_entity(self):
|
||||
output = self._system_settings_entity
|
||||
if output is None:
|
||||
output = SystemSettings(set_studio_state=False)
|
||||
self._system_settings_entity = output
|
||||
|
||||
if self.override_state is OverrideState.DEFAULTS:
|
||||
if output.override_state is not OverrideState.DEFAULTS:
|
||||
output.set_defaults_state()
|
||||
elif self.override_state > OverrideState.DEFAULTS:
|
||||
if output.override_state <= OverrideState.DEFAULTS:
|
||||
try:
|
||||
output.set_studio_state()
|
||||
except Exception:
|
||||
output.set_defaults_state()
|
||||
return output
|
||||
|
||||
def get_entity_from_path(self, path):
|
||||
path_parts = path.split("/")
|
||||
first_part = path_parts[0]
|
||||
# TODO replace with constants
|
||||
if first_part == "system_settings":
|
||||
output = self.system_settings_entity
|
||||
path_parts.pop(0)
|
||||
else:
|
||||
output = self
|
||||
if first_part == "project_settings":
|
||||
path_parts.pop(0)
|
||||
|
||||
for path_part in path_parts:
|
||||
output = output[path_part]
|
||||
return output
|
||||
|
||||
def change_project(self, project_name):
|
||||
if project_name == self._project_name:
|
||||
return
|
||||
|
||||
self._project_name = project_name
|
||||
if project_name is None:
|
||||
self.set_studio_state()
|
||||
return
|
||||
|
||||
project_override_value = {
|
||||
PROJECT_SETTINGS_KEY: get_project_settings_overrides(project_name),
|
||||
PROJECT_ANATOMY_KEY: get_project_anatomy_overrides(project_name)
|
||||
}
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
value = project_override_value.get(key, NOT_SET)
|
||||
child_obj.update_project_value(value)
|
||||
|
||||
self.set_project_state()
|
||||
|
||||
def _reset_values(self):
|
||||
default_values = {
|
||||
PROJECT_SETTINGS_KEY: get_default_settings()[PROJECT_SETTINGS_KEY],
|
||||
PROJECT_ANATOMY_KEY: get_default_settings()[PROJECT_ANATOMY_KEY]
|
||||
}
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
value = default_values.get(key, NOT_SET)
|
||||
child_obj.update_default_value(value)
|
||||
|
||||
studio_overrides = {
|
||||
PROJECT_SETTINGS_KEY: get_studio_project_settings_overrides(),
|
||||
PROJECT_ANATOMY_KEY: get_studio_project_anatomy_overrides()
|
||||
}
|
||||
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
value = studio_overrides.get(key, NOT_SET)
|
||||
child_obj.update_studio_value(value)
|
||||
|
||||
if not self.project_name:
|
||||
return
|
||||
|
||||
project_name = self.project_name
|
||||
project_override_value = {
|
||||
PROJECT_SETTINGS_KEY: get_project_settings_overrides(project_name),
|
||||
PROJECT_ANATOMY_KEY: get_project_anatomy_overrides(project_name)
|
||||
}
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
value = project_override_value.get(key, NOT_SET)
|
||||
child_obj.update_project_value(value)
|
||||
|
||||
def reset(self, new_state=None):
|
||||
"""Discard changes and reset entit's values.
|
||||
|
||||
Reload default values and studio override values and update entities.
|
||||
|
||||
Args:
|
||||
new_state (OverrideState): It is possible to change override state
|
||||
during reset. Current state is used if not defined.
|
||||
"""
|
||||
if new_state is None:
|
||||
new_state = self._override_state
|
||||
|
||||
if new_state is OverrideState.NOT_DEFINED:
|
||||
new_state = OverrideState.DEFAULTS
|
||||
|
||||
self._system_settings_entity = None
|
||||
|
||||
self._reset_values()
|
||||
self.set_override_state(new_state)
|
||||
|
||||
def defaults_dir(self):
|
||||
"""Path to defaults directory.
|
||||
|
||||
Implementation of abstract method.
|
||||
"""
|
||||
return DEFAULTS_DIR
|
||||
|
||||
def _save_studio_values(self):
|
||||
settings_value = self.settings_value()
|
||||
|
||||
self._validate_values_to_save(settings_value)
|
||||
|
||||
self.log.debug("Saving project settings: {}".format(
|
||||
json.dumps(settings_value, indent=4)
|
||||
))
|
||||
project_settings = settings_value.get(PROJECT_SETTINGS_KEY) or {}
|
||||
project_anatomy = settings_value.get(PROJECT_ANATOMY_KEY) or {}
|
||||
|
||||
save_project_settings(self.project_name, project_settings)
|
||||
save_project_anatomy(self.project_name, project_anatomy)
|
||||
|
||||
def _validate_defaults_to_save(self, value):
|
||||
"""Valiations of default values before save."""
|
||||
pass
|
||||
|
||||
def _validate_values_to_save(self, value):
|
||||
pass
|
||||
|
||||
def _save_project_values(self):
|
||||
"""Project overrides are saved same ways as studio overrides."""
|
||||
self._save_studio_values()
|
||||
494
openpype/settings/entities/schemas/README.md
Normal file
494
openpype/settings/entities/schemas/README.md
Normal file
|
|
@ -0,0 +1,494 @@
|
|||
# Creating GUI schemas
|
||||
|
||||
## Basic rules
|
||||
- configurations does not define GUI, but GUI defines configurations!
|
||||
- output is always json (yaml is not needed for anatomy templates anymore)
|
||||
- GUI schema has multiple input types, all inputs are represented by a dictionary
|
||||
- each input may have "input modifiers" (keys in dictionary) that are required or optional
|
||||
- only required modifier for all input items is key `"type"` which says what type of item it is
|
||||
- there are special keys across all inputs
|
||||
- `"is_file"` - this key is for storing openpype defaults in `openpype` repo
|
||||
- reasons of existence: developing new schemas does not require to create defaults manually
|
||||
- key is validated, must be once in hierarchy else it won't be possible to store openpype defaults
|
||||
- `"is_group"` - define that all values under key in hierarchy will be overriden if any value is modified, this information is also stored to overrides
|
||||
- this keys is not allowed for all inputs as they may have not reason for that
|
||||
- key is validated, can be only once in hierarchy but is not required
|
||||
- currently there are `system configurations` and `project configurations`
|
||||
|
||||
## Inner schema
|
||||
- GUI schemas are huge json files, to be able to split whole configuration into multiple schema there's type `schema`
|
||||
- system configuration schemas are stored in `~/tools/settings/settings/gui_schemas/system_schema/` and project configurations in `~/tools/settings/settings/gui_schemas/projects_schema/`
|
||||
- each schema name is filename of json file except extension (without ".json")
|
||||
- if content is dictionary content will be used as `schema` else will be used as `schema_template`
|
||||
|
||||
### schema
|
||||
- can have only key `"children"` which is list of strings, each string should represent another schema (order matters) string represebts name of the schema
|
||||
- will just paste schemas from other schema file in order of "children" list
|
||||
|
||||
```
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "my_schema_name"
|
||||
}
|
||||
```
|
||||
|
||||
### schema_template
|
||||
- allows to define schema "templates" to not duplicate same content multiple times
|
||||
```javascript
|
||||
// EXAMPLE json file content (filename: example_template.json)
|
||||
[
|
||||
{
|
||||
"__default_values__": {
|
||||
"multipath_executables": true
|
||||
}
|
||||
}, {
|
||||
"type": "raw-json",
|
||||
"label": "{host_label} Environments",
|
||||
"key": "{host_name}_environments",
|
||||
"env_group_key": "{host_name}"
|
||||
}, {
|
||||
"type": "path",
|
||||
"key": "{host_name}_executables",
|
||||
"label": "{host_label} - Full paths to executables",
|
||||
"multiplatform": "{multipath_executables}",
|
||||
"multipath": true
|
||||
}
|
||||
]
|
||||
```
|
||||
```javascript
|
||||
// EXAMPLE usage of the template in schema
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "schema_template_examples",
|
||||
"label": "Schema template examples",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
// filename of template (example_template.json)
|
||||
"name": "example_template",
|
||||
"template_data": {
|
||||
"host_label": "Maya 2019",
|
||||
"host_name": "maya_2019",
|
||||
"multipath_executables": false
|
||||
}
|
||||
}, {
|
||||
"type": "schema_template",
|
||||
"name": "example_template",
|
||||
"template_data": {
|
||||
"host_label": "Maya 2020",
|
||||
"host_name": "maya_2020"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
- item in schema mush contain `"type"` and `"name"` keys but it is also expected that `"template_data"` will be entered too
|
||||
- all items in the list, except `__default_values__`, will replace `schema_template` item in schema
|
||||
- template may contain another template or schema
|
||||
- it is expected that schema template will have unfilled fields as in example
|
||||
- unfilled fields are allowed only in values of schema dictionary
|
||||
```javascript
|
||||
{
|
||||
...
|
||||
// Allowed
|
||||
"key": "{to_fill}"
|
||||
...
|
||||
// Not allowed
|
||||
"{to_fill}": "value"
|
||||
...
|
||||
}
|
||||
```
|
||||
- Unfilled fields can be also used for non string values, in that case value must contain only one key and value for fill must contain right type.
|
||||
```javascript
|
||||
{
|
||||
...
|
||||
// Allowed
|
||||
"multiplatform": "{executable_multiplatform}"
|
||||
...
|
||||
// Not allowed
|
||||
"multiplatform": "{executable_multiplatform}_enhanced_string"
|
||||
...
|
||||
}
|
||||
```
|
||||
- It is possible to define default values for unfilled fields to do so one of items in list must be dictionary with key `"__default_values__"` and value as dictionary with default key: values (as in example above).
|
||||
|
||||
|
||||
## Basic Dictionary inputs
|
||||
- these inputs wraps another inputs into {key: value} relation
|
||||
|
||||
## dict
|
||||
- this is another dictionary input wrapping more inputs but visually makes them different
|
||||
- item may be used as widget (in `list` or `dict-modifiable`)
|
||||
- in that case the only key modifier is `children` which is list of it's keys
|
||||
- USAGE: e.g. List of dictionaries where each dictionary have same structure.
|
||||
- item may be with or without `"label"` if is not used as widget
|
||||
- required keys are `"key"` under which will be stored
|
||||
- without label it is just wrap item holding `"key"`
|
||||
- can't have `"is_group"` key set to True as it breaks visual override showing
|
||||
- if `"label"` is entetered there which will be shown in GUI
|
||||
- item with label can be collapsible
|
||||
- that can be set with key `"collapsible"` as `True`/`False` (Default: `True`)
|
||||
- with key `"collapsed"` as `True`/`False` can be set that is collapsed when GUI is opened (Default: `False`)
|
||||
- it is possible to add darker background with `"highlight_content"` (Default: `False`)
|
||||
- darker background has limits of maximum applies after 3-4 nested highlighted items there is not difference in the color
|
||||
- output is dictionary `{the "key": children values}`
|
||||
```
|
||||
# Example
|
||||
{
|
||||
"key": "applications",
|
||||
"type": "dict",
|
||||
"label": "Applications",
|
||||
"collapsible": true,
|
||||
"highlight_content": true,
|
||||
"is_group": true,
|
||||
"is_file": true,
|
||||
"children": [
|
||||
...ITEMS...
|
||||
]
|
||||
}
|
||||
|
||||
# Without label
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "global",
|
||||
"children": [
|
||||
...ITEMS...
|
||||
]
|
||||
}
|
||||
|
||||
# When used as widget
|
||||
{
|
||||
"type": "list",
|
||||
"key": "profiles",
|
||||
"label": "Profiles",
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"key": "families",
|
||||
"label": "Families",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
}, {
|
||||
"key": "hosts",
|
||||
"label": "Hosts",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
}
|
||||
...
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Inputs for setting any kind of value (`Pure` inputs)
|
||||
- all these input must have defined `"key"` under which will be stored and `"label"` which will be shown next to input
|
||||
- unless they are used in different types of inputs (later) "as widgets" in that case `"key"` and `"label"` are not required as there is not place where to set them
|
||||
|
||||
### boolean
|
||||
- simple checkbox, nothing more to set
|
||||
```
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "my_boolean_key",
|
||||
"label": "Do you want to use Pype?"
|
||||
}
|
||||
```
|
||||
|
||||
### number
|
||||
- number input, can be used for both integer and float
|
||||
- key `"decimal"` defines how many decimal places will be used, 0 is for integer input (Default: `0`)
|
||||
- key `"minimum"` as minimum allowed number to enter (Default: `-99999`)
|
||||
- key `"maxium"` as maximum allowed number to enter (Default: `99999`)
|
||||
```
|
||||
{
|
||||
"type": "number",
|
||||
"key": "fps",
|
||||
"label": "Frame rate (FPS)"
|
||||
"decimal": 2,
|
||||
"minimum": 1,
|
||||
"maximum": 300000
|
||||
}
|
||||
```
|
||||
|
||||
### text
|
||||
- simple text input
|
||||
- key `"multiline"` allows to enter multiple lines of text (Default: `False`)
|
||||
- key `"placeholder"` allows to show text inside input when is empty (Default: `None`)
|
||||
|
||||
```
|
||||
{
|
||||
"type": "text",
|
||||
"key": "deadline_pool",
|
||||
"label": "Deadline pool"
|
||||
}
|
||||
```
|
||||
|
||||
### path-input
|
||||
- enhanced text input
|
||||
- does not allow to enter backslash, is auto-converted to forward slash
|
||||
- may be added another validations, like do not allow end path with slash
|
||||
- this input is implemented to add additional features to text input
|
||||
- this is meant to be used in proxy input `path-widget`
|
||||
- DO NOT USE this input in schema please
|
||||
|
||||
### raw-json
|
||||
- a little bit enhanced text input for raw json
|
||||
- has validations of json format
|
||||
- empty value is invalid value, always must be json serializable
|
||||
- valid value types are list `[]` and dictionary `{}`
|
||||
- schema also defines valid value type
|
||||
- by default it is dictionary
|
||||
- to be able use list it is required to define `is_list` to `true`
|
||||
```
|
||||
{
|
||||
"type": "raw-json",
|
||||
"key": "profiles",
|
||||
"label": "Extract Review profiles",
|
||||
"is_list": true
|
||||
}
|
||||
```
|
||||
|
||||
### enum
|
||||
- returns value of single on multiple items from predefined values
|
||||
- multiselection can be allowed with setting key `"multiselection"` to `True` (Default: `False`)
|
||||
- values are defined under value of key `"enum_items"` as list
|
||||
- each item in list is simple dictionary where value is label and key is value which will be stored
|
||||
- should be possible to enter single dictionary if order of items doesn't matter
|
||||
|
||||
```
|
||||
{
|
||||
"key": "tags",
|
||||
"label": "Tags",
|
||||
"type": "enum",
|
||||
"multiselection": true,
|
||||
"enum_items": [
|
||||
{"burnin": "Add burnins"},
|
||||
{"ftrackreview": "Add to Ftrack"},
|
||||
{"delete": "Delete output"},
|
||||
{"slate-frame": "Add slate frame"},
|
||||
{"no-hnadles": "Skip handle frames"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Inputs for setting value using Pure inputs
|
||||
- these inputs also have required `"key"`
|
||||
- attribute `"label"` is required in few conditions
|
||||
- when item is marked `as_group` or when `use_label_wrap`
|
||||
- they use Pure inputs "as widgets"
|
||||
|
||||
### list
|
||||
- output is list
|
||||
- items can be added and removed
|
||||
- items in list must be the same type
|
||||
- to wrap item in collapsible widget with label on top set `use_label_wrap` to `True`
|
||||
- when this is used `collapsible` and `collapsed` can be set (same as `dict` item does)
|
||||
- type of items is defined with key `"object_type"`
|
||||
- there are 2 possible ways how to set the type:
|
||||
1.) dictionary with item modifiers (`number` input has `minimum`, `maximum` and `decimals`) in that case item type must be set as value of `"type"` (example below)
|
||||
2.) item type name as string without modifiers (e.g. `text`)
|
||||
|
||||
1.) with item modifiers
|
||||
```
|
||||
{
|
||||
"type": "list",
|
||||
"key": "exclude_ports",
|
||||
"label": "Exclude ports",
|
||||
"object_type": {
|
||||
"type": "number", # number item type
|
||||
"minimum": 1, # minimum modifier
|
||||
"maximum": 65535 # maximum modifier
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2.) without modifiers
|
||||
```
|
||||
{
|
||||
"type": "list",
|
||||
"key": "exclude_ports",
|
||||
"label": "Exclude ports",
|
||||
"object_type": "text"
|
||||
}
|
||||
```
|
||||
|
||||
### dict-modifiable
|
||||
- one of dictionary inputs, this is only used as value input
|
||||
- items in this input can be removed and added same way as in `list` input
|
||||
- value items in dictionary must be the same type
|
||||
- type of items is defined with key `"object_type"`
|
||||
- required keys may be defined under `"required_keys"`
|
||||
- required keys must be defined as a list (e.g. `["key_1"]`) and are moved to the top
|
||||
- these keys can't be removed or edited (it is possible to edit label if item is collapsible)
|
||||
- there are 2 possible ways how to set the type:
|
||||
1.) dictionary with item modifiers (`number` input has `minimum`, `maximum` and `decimals`) in that case item type must be set as value of `"type"` (example below)
|
||||
2.) item type name as string without modifiers (e.g. `text`)
|
||||
- this input can be collapsible
|
||||
- that can be set with key `"collapsible"` as `True`/`False` (Default: `True`)
|
||||
- with key `"collapsed"` as `True`/`False` can be set that is collapsed when GUI is opened (Default: `False`)
|
||||
|
||||
1.) with item modifiers
|
||||
```
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"object_type": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 300
|
||||
},
|
||||
"is_group": true,
|
||||
"key": "templates_mapping",
|
||||
"label": "Muster - Templates mapping",
|
||||
"is_file": true
|
||||
}
|
||||
```
|
||||
|
||||
2.) without modifiers
|
||||
```
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"object_type": "text",
|
||||
"is_group": true,
|
||||
"key": "templates_mapping",
|
||||
"label": "Muster - Templates mapping",
|
||||
"is_file": true
|
||||
}
|
||||
```
|
||||
|
||||
### path-widget
|
||||
- input for paths, use `path-input` internally
|
||||
- has 2 input modifiers `"multiplatform"` and `"multipath"`
|
||||
- `"multiplatform"` - adds `"windows"`, `"linux"` and `"darwin"` path inputs result is dictionary
|
||||
- `"multipath"` - it is possible to enter multiple paths
|
||||
- if both are enabled result is dictionary with lists
|
||||
|
||||
```
|
||||
{
|
||||
"type": "path",
|
||||
"key": "ffmpeg_path",
|
||||
"label": "FFmpeg path",
|
||||
"multiplatform": true,
|
||||
"multipath": true
|
||||
}
|
||||
```
|
||||
|
||||
### list-strict
|
||||
- input for strict number of items in list
|
||||
- each child item can be different type with different possible modifiers
|
||||
- it is possible to display them in horizontal or vertical layout
|
||||
- key `"horizontal"` as `True`/`False` (Default: `True`)
|
||||
- each child may have defined `"label"` which is shown next to input
|
||||
- label does not reflect modifications or overrides (TODO)
|
||||
- children item are defined under key `"object_types"` which is list of dictionaries
|
||||
- key `"children"` is not used because is used for hierarchy validations in schema
|
||||
- USAGE: For colors, transformations, etc. Custom number and different modifiers
|
||||
give ability to define if color is HUE or RGB, 0-255, 0-1, 0-100 etc.
|
||||
|
||||
```
|
||||
{
|
||||
"type": "list-strict",
|
||||
"key": "color",
|
||||
"label": "Color",
|
||||
"object_types": [
|
||||
{
|
||||
"label": "Red",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 255,
|
||||
"decimal": 0
|
||||
}, {
|
||||
"label": "Green",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 255,
|
||||
"decimal": 0
|
||||
}, {
|
||||
"label": "Blue",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 255,
|
||||
"decimal": 0
|
||||
}, {
|
||||
"label": "Alpha",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 6
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Noninteractive widgets
|
||||
- have nothing to do with data
|
||||
|
||||
### label
|
||||
- add label with note or explanations
|
||||
- it is possible to use html tags inside the label
|
||||
|
||||
```
|
||||
{
|
||||
"type": "label",
|
||||
"label": "<span style=\"color:#FF0000\";>RED LABEL:</span> Normal label"
|
||||
}
|
||||
```
|
||||
|
||||
### splitter
|
||||
- visual splitter of items (more divider than splitter)
|
||||
|
||||
```
|
||||
{
|
||||
"type": "splitter"
|
||||
}
|
||||
```
|
||||
|
||||
## Proxy wrappers
|
||||
- should wraps multiple inputs only visually
|
||||
- these does not have `"key"` key and do not allow to have `"is_file"` or `"is_group"` modifiers enabled
|
||||
- can't be used as widget (first item in e.g. `list`, `dict-modifiable`, etc.)
|
||||
|
||||
### form
|
||||
- wraps inputs into form look layout
|
||||
- should be used only for Pure inputs
|
||||
|
||||
```
|
||||
{
|
||||
"type": "dict-form",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "deadline_department",
|
||||
"label": "Deadline apartment"
|
||||
}, {
|
||||
"type": "number",
|
||||
"key": "deadline_priority",
|
||||
"label": "Deadline priority"
|
||||
}, {
|
||||
...
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### collapsible-wrap
|
||||
- wraps inputs into collapsible widget
|
||||
- looks like `dict` but does not hold `"key"`
|
||||
- should be used only for Pure inputs
|
||||
|
||||
```
|
||||
{
|
||||
"type": "collapsible-wrap",
|
||||
"label": "Collapsible example"
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "_example_input_collapsible",
|
||||
"label": "Example input in collapsible wrapper"
|
||||
}, {
|
||||
...
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
{
|
||||
"key": "project",
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"type": "anatomy",
|
||||
"key": "project_anatomy",
|
||||
"label": "Anatomy",
|
||||
"children": [
|
||||
{
|
||||
"key": "roots",
|
||||
"label": "Roots",
|
||||
"type": "dict-modifiable",
|
||||
"is_file": true,
|
||||
"is_group": true,
|
||||
"expandable": false,
|
||||
"object_type": {
|
||||
"type": "path",
|
||||
"multiplatform": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_anatomy_templates"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_anatomy_attributes"
|
||||
},
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"key": "tasks",
|
||||
"label": "Task types",
|
||||
"is_file": true,
|
||||
"is_group": true,
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "short_name",
|
||||
"label": "Short name"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_anatomy_imageio"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "project_settings",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_project_global"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_project_ftrack"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_project_deadline"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_project_maya"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_project_nuke"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_project_hiero"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_project_harmony"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_project_celaction"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_project_resolve"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_project_standalonepublisher"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_project_unreal"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "celaction",
|
||||
"label": "CelAction",
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "publish",
|
||||
"label": "Publish plugins",
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"key": "ExtractCelactionDeadline",
|
||||
"label": "ExtractCelactionDeadline",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "deadline_department",
|
||||
"label": "Deadline apartment"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "deadline_priority",
|
||||
"label": "Deadline priority"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "deadline_pool",
|
||||
"label": "Deadline pool"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "deadline_pool_secondary",
|
||||
"label": "Deadline pool (secondary)"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "deadline_group",
|
||||
"label": "Deadline Group"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "deadline_chunk_size",
|
||||
"label": "Deadline Chunk size"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "deadline",
|
||||
"label": "Deadline",
|
||||
"collapsible": true,
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "publish",
|
||||
"label": "Publish plugins",
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "MayaSubmitDeadline",
|
||||
"label": "Submit maya job to deadline",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "optional",
|
||||
"label": "Optional"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "active",
|
||||
"label": "Active"
|
||||
},
|
||||
{
|
||||
"type": "enum",
|
||||
"key": "tile_assembler_plugin",
|
||||
"label": "Tile Assembler Plugin",
|
||||
"multiselection": false,
|
||||
"enum_items": [
|
||||
{
|
||||
"DraftTileAssembler": "Draft Tile Assembler"
|
||||
},
|
||||
{
|
||||
"oiio": "Open Image IO"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "use_published",
|
||||
"label": "Use Published scene"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "asset_dependencies",
|
||||
"label": "Use Asset dependencies"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "group",
|
||||
"label": "Group Name"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "limit",
|
||||
"label": "Limit Groups",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "NukeSubmitDeadline",
|
||||
"label": "Nuke Submit to Deadline",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "optional",
|
||||
"label": "Optional"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "active",
|
||||
"label": "Active"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "use_published",
|
||||
"label": "Use Published scene"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "priority",
|
||||
"label": "Priority"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "chunk_size",
|
||||
"label": "Chunk Size"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "primary_pool",
|
||||
"label": "Primary Pool"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "secondary_pool",
|
||||
"label": "Secondary Pool"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "group",
|
||||
"label": "Group"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "department",
|
||||
"label": "Department"
|
||||
},
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"key": "limit_groups",
|
||||
"label": "Limit Groups",
|
||||
"object_type": {
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "HarmonySubmitDeadline",
|
||||
"label": "Harmony Submit to Deadline",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "optional",
|
||||
"label": "Optional"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "active",
|
||||
"label": "Active"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "use_published",
|
||||
"label": "Use Published scene"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "priority",
|
||||
"label": "Priority"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "chunk_size",
|
||||
"label": "Chunk Size"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "primary_pool",
|
||||
"label": "Primary Pool"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "secondary_pool",
|
||||
"label": "Secondary Pool"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "group",
|
||||
"label": "Group"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "department",
|
||||
"label": "Department"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "AfterEffectsSubmitDeadline",
|
||||
"label": "After Effects Submit to Deadline",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "optional",
|
||||
"label": "Optional"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "active",
|
||||
"label": "Active"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "use_published",
|
||||
"label": "Use Published scene"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "priority",
|
||||
"label": "Priority"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "chunk_size",
|
||||
"label": "Chunk Size"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "primary_pool",
|
||||
"label": "Primary Pool"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "secondary_pool",
|
||||
"label": "Secondary Pool"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "group",
|
||||
"label": "Group"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "department",
|
||||
"label": "Department"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,645 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "ftrack",
|
||||
"label": "Ftrack",
|
||||
"collapsible": true,
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "events",
|
||||
"label": "Server Actions/Events",
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "sync_to_avalon",
|
||||
"label": "Sync to avalon",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Allow name and hierarchy change only if following statuses are on all children tasks"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "statuses_name_change",
|
||||
"label": "Statuses",
|
||||
"object_type": {
|
||||
"type": "text",
|
||||
"multiline": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "sync_hier_entity_attributes",
|
||||
"label": "Sync Hierarchical and Entity Attributes",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "interest_entity_types",
|
||||
"label": "Entity types of interest",
|
||||
"object_type": {
|
||||
"type": "text",
|
||||
"multiline": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "interest_attributes",
|
||||
"label": "Attributes to sync",
|
||||
"object_type": {
|
||||
"type": "text",
|
||||
"multiline": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "action_enabled",
|
||||
"label": "Enable Action"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "role_list",
|
||||
"label": "Roles for action",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "clone_review_session",
|
||||
"label": "Clone Review Session",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "role_list",
|
||||
"label": "Roles for action",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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": "dict",
|
||||
"key": "user_assignment",
|
||||
"label": "Run script on user assignments",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "status_update",
|
||||
"label": "Update status on task action",
|
||||
"is_group": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"key": "mapping",
|
||||
"type": "dict-modifiable",
|
||||
"object_type": {
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "status_task_to_parent",
|
||||
"label": "Sync status from Task to Parent",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "List of parent object types where this is triggered (\"Shot\", \"Asset Build\", etc.). Skipped if list is empty."
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"object_type": "text",
|
||||
"key": "parent_object_types",
|
||||
"label": "Object types"
|
||||
},
|
||||
{
|
||||
"key": "parent_status_match_all_task_statuses",
|
||||
"type": "dict-modifiable",
|
||||
"label": "Change parent if all tasks match",
|
||||
"object_type": {
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "parent_status_by_task_status",
|
||||
"label": "Change parent status if a single task matches",
|
||||
"use_label_wrap": true,
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"label": "New parent status",
|
||||
"key": "new_status"
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"label": "Task status",
|
||||
"key": "task_statuses",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "status_task_to_version",
|
||||
"label": "Sync status from Task to Version",
|
||||
"is_group": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"key": "mapping",
|
||||
"object_type":
|
||||
{
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "<b>Limit<b/> status changes to entered asset types. Limitation is ignored if nothing is entered."
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "asset_types_filter",
|
||||
"label": "Asset types (short)",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "status_version_to_task",
|
||||
"label": "Sync status from Version to Task",
|
||||
"is_group": true,
|
||||
"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",
|
||||
"is_group": true,
|
||||
"label": "Update status on next task",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Change status on next task by <b>task types order</b> when task status state changed to \"Done\". All tasks with same Task type must be \"Done\"."
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Mapping of next task status changes <b>From</b> -> <b>To</b>."
|
||||
},
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"key": "mapping",
|
||||
"object_type": {
|
||||
"type": "text"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Status names that are ignored on \"Done\" check (e.g. \"Omitted\")."
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "ignored_statuses",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Allow to break rule that all tasks with same Task type must be \"Done\" and change statuses with same type tasks ordered by name."
|
||||
},
|
||||
{
|
||||
"label": "Name sorting",
|
||||
"type": "boolean",
|
||||
"key": "name_sorting"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "user_handlers",
|
||||
"label": "User Actions/Events",
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "application_launch_statuses",
|
||||
"is_group": true,
|
||||
"label": "Application - Status change on launch",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "<b>Do not change status if current status is:</b>"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "ignored_statuses",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Change task's status to <b>left side</b> if current task status is in list on <b>right side</b>."
|
||||
},
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"key": "status_change",
|
||||
"object_type": {
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "create_update_attributes",
|
||||
"label": "Create/Update Avalon Attributes",
|
||||
"children": [
|
||||
{
|
||||
"type": "list",
|
||||
"key": "role_list",
|
||||
"label": "Roles",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "prepare_project",
|
||||
"label": "Prepare Project",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "role_list",
|
||||
"label": "Roles",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "clean_hierarchical_attr",
|
||||
"label": "Clean hierarchical custom attributes",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "role_list",
|
||||
"label": "Roles",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "delete_asset_subset",
|
||||
"label": "Delete Asset/Subsets",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "role_list",
|
||||
"label": "Roles",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "delete_old_versions",
|
||||
"label": "Delete old versions",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "role_list",
|
||||
"label": "Roles",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "delivery_action",
|
||||
"label": "Delivery",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "role_list",
|
||||
"label": "Roles",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "store_thubmnail_to_avalon",
|
||||
"label": "Store Thumbnails to avalon",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "role_list",
|
||||
"label": "Roles",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "job_killer",
|
||||
"label": "Job Killer",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "role_list",
|
||||
"label": "Roles",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "sync_to_avalon_local",
|
||||
"label": "Sync to avalon (local) - For development",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "role_list",
|
||||
"label": "Roles",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "seed_project",
|
||||
"label": "Seed Debug Project",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "role_list",
|
||||
"label": "Roles",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "publish",
|
||||
"label": "Publish plugins",
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"key": "IntegrateFtrackNote",
|
||||
"label": "IntegrateFtrackNote",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "note_with_intent_template",
|
||||
"label": "Note with intent template"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"object_type": "text",
|
||||
"key": "note_labels",
|
||||
"label": "Note labels"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"key": "ValidateFtrackAttributes",
|
||||
"label": "ValidateFtrackAttributes",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "raw-json",
|
||||
"key": "ftrack_custom_attributes",
|
||||
"label": "Custom attributes to validate"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "global",
|
||||
"label": "Global",
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_global_publish"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_global_tools"
|
||||
},
|
||||
{
|
||||
"type": "raw-json",
|
||||
"label": "Project Folder Structure",
|
||||
"key": "project_folder_structure",
|
||||
"use_label_wrap": true
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_project_syncserver"
|
||||
},
|
||||
{
|
||||
"key": "project_plugins",
|
||||
"type": "path",
|
||||
"label": "Additional Project Plugin Paths",
|
||||
"multiplatform": true,
|
||||
"multipath": true,
|
||||
"use_label_wrap": true
|
||||
},
|
||||
{
|
||||
"key": "project_environments",
|
||||
"type": "raw-json",
|
||||
"label": "Additional Project Environments (set on application launch)",
|
||||
"use_label_wrap": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "harmony",
|
||||
"label": "Harmony",
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "general",
|
||||
"label": "General",
|
||||
"children": [
|
||||
{
|
||||
"type": "list",
|
||||
"key": "skip_resolution_check",
|
||||
"object_type": "text",
|
||||
"label": "Skip Resolution Check for Tasks"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "skip_timelines_check",
|
||||
"object_type": "text",
|
||||
"label": "Skip Timeliene Check for Tasks"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "publish",
|
||||
"label": "Publish plugins",
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "CollectPalettes",
|
||||
"label": "Collect Palettes",
|
||||
"children": [
|
||||
{
|
||||
"type": "list",
|
||||
"key": "allowed_tasks",
|
||||
"label": "Allowed tasks",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "HarmonySubmitDeadline",
|
||||
"label": "Harmony Submit to Deadline",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "use_published",
|
||||
"label": "Use Published scene"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "priority",
|
||||
"label": "priority"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "primary_pool",
|
||||
"label": "Primary Pool"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "secondary_pool",
|
||||
"label": "Secondary Pool"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "chunk_size",
|
||||
"label": "Chunk Size"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "hiero",
|
||||
"label": "Hiero",
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "create",
|
||||
"label": "Create plugins",
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "CreateShotClip",
|
||||
"label": "Create Shot Clip",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "collapsible-wrap",
|
||||
"label": "Shot Hierarchy And Rename Settings",
|
||||
"collapsible": false,
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "hierarchy",
|
||||
"label": "Shot parent hierarchy"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "clipRename",
|
||||
"label": "Rename clips"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "clipName",
|
||||
"label": "Clip name template"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "countFrom",
|
||||
"label": "Count sequence from"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "countSteps",
|
||||
"label": "Stepping number"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "collapsible-wrap",
|
||||
"label": "Shot Template Keywords",
|
||||
"collapsible": false,
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "folder",
|
||||
"label": "{folder}"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "episode",
|
||||
"label": "{episode}"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "sequence",
|
||||
"label": "{sequence}"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "track",
|
||||
"label": "{track}"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "shot",
|
||||
"label": "{shot}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "collapsible-wrap",
|
||||
"label": "Vertical Synchronization Of Attributes",
|
||||
"collapsible": false,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "vSyncOn",
|
||||
"label": "Enable Vertical Sync"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "collapsible-wrap",
|
||||
"label": "Shot Attributes",
|
||||
"collapsible": false,
|
||||
"children": [
|
||||
{
|
||||
"type": "number",
|
||||
"key": "workfileFrameStart",
|
||||
"label": "Workfiles Start Frame"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "handleStart",
|
||||
"label": "Handle start (head)"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "handleEnd",
|
||||
"label": "Handle end (tail)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "publish",
|
||||
"label": "Publish plugins",
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"key": "CollectInstanceVersion",
|
||||
"label": "Collect Instance Version",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"key": "ExtractReviewCutUpVideo",
|
||||
"label": "Extract Review Cut Up Video",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"object_type": "text",
|
||||
"key": "tags_addition",
|
||||
"label": "Tags addition"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_publish_gui_filter"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "maya",
|
||||
"label": "Maya",
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"key": "ext_mapping",
|
||||
"label": "Extension Mapping",
|
||||
"use_label_wrap": true,
|
||||
"object_type": {
|
||||
"type": "text"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_maya_create"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_maya_publish"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_maya_load"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_workfile_build"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_publish_gui_filter"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "nuke",
|
||||
"label": "Nuke",
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "general",
|
||||
"label": "General",
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "menu",
|
||||
"label": "OpenPype Menu shortcuts",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "create",
|
||||
"label": "Create..."
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "publish",
|
||||
"label": "Publish..."
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "load",
|
||||
"label": "Load..."
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "manage",
|
||||
"label": "Manage..."
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "build_workfile",
|
||||
"label": "Build Workfile"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "create",
|
||||
"label": "Creator plugins",
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": false,
|
||||
"key": "CreateWriteRender",
|
||||
"label": "CreateWriteRender",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "fpath_template",
|
||||
"label": "Path template"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": false,
|
||||
"key": "CreateWritePrerender",
|
||||
"label": "CreateWritePrerender",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "fpath_template",
|
||||
"label": "Path template"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_nuke_publish",
|
||||
"template_data": []
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_nuke_load",
|
||||
"template_data": []
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_workfile_build"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_publish_gui_filter"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "resolve",
|
||||
"label": "DaVinci Resolve",
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "create",
|
||||
"label": "Creator plugins",
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "CreateShotClip",
|
||||
"label": "Create Shot Clip",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "collapsible-wrap",
|
||||
"label": "Shot Hierarchy And Rename Settings",
|
||||
"collapsible": false,
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "hierarchy",
|
||||
"label": "Shot parent hierarchy"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "clipRename",
|
||||
"label": "Rename clips"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "clipName",
|
||||
"label": "Clip name template"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "countFrom",
|
||||
"label": "Count sequence from"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "countSteps",
|
||||
"label": "Stepping number"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "collapsible-wrap",
|
||||
"label": "Shot Template Keywords",
|
||||
"collapsible": false,
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "folder",
|
||||
"label": "{folder}"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "episode",
|
||||
"label": "{episode}"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "sequence",
|
||||
"label": "{sequence}"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "track",
|
||||
"label": "{track}"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "shot",
|
||||
"label": "{shot}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "collapsible-wrap",
|
||||
"label": "Vertical Synchronization Of Attributes",
|
||||
"collapsible": false,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "vSyncOn",
|
||||
"label": "Enable Vertical Sync"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "collapsible-wrap",
|
||||
"label": "Shot Attributes",
|
||||
"collapsible": false,
|
||||
"children": [
|
||||
{
|
||||
"type": "number",
|
||||
"key": "workfileFrameStart",
|
||||
"label": "Workfiles Start Frame"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "handleStart",
|
||||
"label": "Handle start (head)"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "handleEnd",
|
||||
"label": "Handle end (tail)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "standalonepublisher",
|
||||
"label": "Standalone Publisher",
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"collapsible": true,
|
||||
"key": "create",
|
||||
"label": "Creator plugins",
|
||||
"collapsible_key": true,
|
||||
"is_file": true,
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "name",
|
||||
"label": "Name"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "label",
|
||||
"label": "Label"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "family",
|
||||
"label": "Family"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "icon",
|
||||
"label": "Icon"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "defaults",
|
||||
"label": "Defaults",
|
||||
"object_type": {
|
||||
"type": "text"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "help",
|
||||
"label": "Help"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "publish",
|
||||
"label": "Publish plugins",
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "ExtractThumbnailSP",
|
||||
"label": "ExtractThumbnailSP",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": false,
|
||||
"key": "ffmpeg_args",
|
||||
"label": "ffmpeg_args",
|
||||
"children": [
|
||||
{
|
||||
"type": "list",
|
||||
"object_type": "text",
|
||||
"key": "input",
|
||||
"label": "input"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"object_type": "text",
|
||||
"key": "output",
|
||||
"label": "output"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "sync_server",
|
||||
"label": "Sync Server (currently unused)",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "config",
|
||||
"label": "Config",
|
||||
"collapsible": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "retry_cnt",
|
||||
"label": "Retry Count"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "loop_delay",
|
||||
"label": "Loop Delay"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "active_site",
|
||||
"label": "Active Site"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "remote_site",
|
||||
"label": "Remote Site"
|
||||
}
|
||||
]
|
||||
}, {
|
||||
"type": "dict-modifiable",
|
||||
"collapsible": true,
|
||||
"key": "sites",
|
||||
"label": "Sites",
|
||||
"collapsible_key": false,
|
||||
"is_file": true,
|
||||
"object_type":
|
||||
{
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "provider",
|
||||
"label": "Provider"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "credentials_url",
|
||||
"label": "Credentials url"
|
||||
},
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"key": "root",
|
||||
"label": "Roots",
|
||||
"collapsable": false,
|
||||
"collapsable_key": false,
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "unreal",
|
||||
"label": "Unreal Engine",
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "project_setup",
|
||||
"label": "Project Setup",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "dev_mode",
|
||||
"label": "Dev mode"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "install_unreal_python_engine",
|
||||
"label": "Install unreal python engine"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "attributes",
|
||||
"label": "Attributes",
|
||||
"is_file": true,
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "number",
|
||||
"key": "fps",
|
||||
"label": "Frame Rate",
|
||||
"decimal": 2,
|
||||
"minimum": 0
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "frameStart",
|
||||
"label": "Frame Start"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "frameEnd",
|
||||
"label": "Frame End"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "clipIn",
|
||||
"label": "Clip In"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "clipOut",
|
||||
"label": "Clip Out"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "handleStart",
|
||||
"label": "Handle Start"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "handleEnd",
|
||||
"label": "Handle End"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "resolutionWidth",
|
||||
"label": "Resolution Width"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "resolutionHeight",
|
||||
"label": "Resolution Height"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "pixelAspect",
|
||||
"label": "Pixel Aspect Ratio",
|
||||
"decimal": 2,
|
||||
"minimum": 0
|
||||
},
|
||||
{
|
||||
"type": "apps-enum",
|
||||
"key": "applications",
|
||||
"label": "Applications"
|
||||
},
|
||||
{
|
||||
"type": "tools-enum",
|
||||
"key": "tools_env",
|
||||
"label": "Tools"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,352 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "imageio",
|
||||
"label": "Color Management and Output Formats",
|
||||
"is_file": true,
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"key": "hiero",
|
||||
"type": "dict",
|
||||
"label": "Hiero",
|
||||
"children": [
|
||||
{
|
||||
"key": "workfile",
|
||||
"type": "dict",
|
||||
"label": "Workfile",
|
||||
"collapsible": false,
|
||||
"children": [
|
||||
{
|
||||
"type": "form",
|
||||
"children": [
|
||||
{
|
||||
"type": "enum",
|
||||
"key": "ocioConfigName",
|
||||
"label": "OpenColorIO Config",
|
||||
"enum_items": [
|
||||
{
|
||||
"nuke-default": "nuke-default"
|
||||
},
|
||||
{
|
||||
"aces_1.0.3": "aces_1.0.3"
|
||||
},
|
||||
{
|
||||
"aces_1.1": "aces_1.1"
|
||||
},
|
||||
{
|
||||
"custom": "custom"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"key": "ocioconfigpath",
|
||||
"label": "Custom OCIO path",
|
||||
"multiplatform": true,
|
||||
"multipath": true
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "workingSpace",
|
||||
"label": "Working Space"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "sixteenBitLut",
|
||||
"label": "16 Bit Files"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "eightBitLut",
|
||||
"label": "8 Bit Files"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "floatLut",
|
||||
"label": "Floating Point Files"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "logLut",
|
||||
"label": "Log Files"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "viewerLut",
|
||||
"label": "Viewer"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "thumbnailLut",
|
||||
"label": "Thumbnails"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "regexInputs",
|
||||
"type": "dict",
|
||||
"label": "Colorspace on Inputs by regex detection",
|
||||
"collapsible": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "list",
|
||||
"key": "inputs",
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "regex",
|
||||
"label": "Regex"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "colorspace",
|
||||
"label": "Colorspace"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "nuke",
|
||||
"type": "dict",
|
||||
"label": "Nuke",
|
||||
"children": [
|
||||
{
|
||||
"key": "workfile",
|
||||
"type": "dict",
|
||||
"label": "Workfile",
|
||||
"collapsible": false,
|
||||
"children": [
|
||||
{
|
||||
"type": "form",
|
||||
"children": [
|
||||
{
|
||||
"type": "enum",
|
||||
"key": "colorManagement",
|
||||
"label": "color management",
|
||||
"enum_items": [
|
||||
{
|
||||
"Nuke": "Nuke"
|
||||
},
|
||||
{
|
||||
"OCIO": "OCIO"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "enum",
|
||||
"key": "OCIO_config",
|
||||
"label": "OpenColorIO Config",
|
||||
"enum_items": [
|
||||
{
|
||||
"nuke-default": "nuke-default"
|
||||
},
|
||||
{
|
||||
"spi-vfx": "spi-vfx"
|
||||
},
|
||||
{
|
||||
"spi-anim": "spi-anim"
|
||||
},
|
||||
{
|
||||
"aces_0.1.1": "aces_0.1.1"
|
||||
},
|
||||
{
|
||||
"aces_0.7.1": "aces_0.7.1"
|
||||
},
|
||||
{
|
||||
"aces_1.0.1": "aces_1.0.1"
|
||||
},
|
||||
{
|
||||
"aces_1.0.3": "aces_1.0.3"
|
||||
},
|
||||
{
|
||||
"aces_1.1": "aces_1.1"
|
||||
},
|
||||
{
|
||||
"custom": "custom"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"key": "customOCIOConfigPath",
|
||||
"label": "Custom OCIO config path",
|
||||
"multiplatform": true,
|
||||
"multipath": true
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "workingSpaceLUT",
|
||||
"label": "Working Space"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "monitorLut",
|
||||
"label": "monitor"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "int8Lut",
|
||||
"label": "8-bit files"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "int16Lut",
|
||||
"label": "16-bit files"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "logLut",
|
||||
"label": "log files"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "floatLut",
|
||||
"label": "float files"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "nodes",
|
||||
"type": "dict",
|
||||
"label": "Nodes",
|
||||
"collapsible": true,
|
||||
"children": [
|
||||
{
|
||||
"key": "requiredNodes",
|
||||
"type": "list",
|
||||
"label": "Required Nodes",
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"type": "list",
|
||||
"key": "plugins",
|
||||
"label": "Used in plugins",
|
||||
"object_type": {
|
||||
"type": "text",
|
||||
"key": "pluginClass",
|
||||
"label": "Plugin Class"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "nukeNodeClass",
|
||||
"label": "Nuke Node Class"
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"key": "knobs",
|
||||
"label": "Knobs",
|
||||
"type": "list",
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "name",
|
||||
"label": "Name"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "value",
|
||||
"label": "Value"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "customNodes",
|
||||
"label": "Custom Nodes",
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"type": "list",
|
||||
"key": "plugins",
|
||||
"label": "Used in plugins",
|
||||
"object_type": {
|
||||
"type": "text",
|
||||
"key": "pluginClass",
|
||||
"label": "Plugin Class"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "nukeNodeClass",
|
||||
"label": "Nuke Node Class"
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"key": "knobs",
|
||||
"label": "Knobs",
|
||||
"type": "list",
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "name",
|
||||
"label": "Name"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "value",
|
||||
"label": "Value"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "regexInputs",
|
||||
"type": "dict",
|
||||
"label": "Colorspace on Inputs by regex detection",
|
||||
"collapsible": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "list",
|
||||
"key": "inputs",
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "regex",
|
||||
"label": "Regex"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "colorspace",
|
||||
"label": "Colorspace"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "templates",
|
||||
"label": "Templates",
|
||||
"collapsible": true,
|
||||
"collapsible_key": true,
|
||||
"is_file": true,
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "defaults",
|
||||
"children": [
|
||||
{
|
||||
"type": "number",
|
||||
"key": "version_padding",
|
||||
"label": "Version Padding",
|
||||
"minimum": 1,
|
||||
"maximum": 10
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "version",
|
||||
"label": "Version"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "frame_padding",
|
||||
"label": "Frame Padding",
|
||||
"minimum": 1,
|
||||
"maximum": 10
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "frame",
|
||||
"label": "Frame"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "work",
|
||||
"label": "Work",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "folder",
|
||||
"label": "Folder"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "file",
|
||||
"label": "File"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "path",
|
||||
"label": "Path"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "render",
|
||||
"label": "Render",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "folder",
|
||||
"label": "Folder"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "file",
|
||||
"label": "File"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "path",
|
||||
"label": "Path"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "publish",
|
||||
"label": "Publish",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "folder",
|
||||
"label": "Folder"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "file",
|
||||
"label": "File"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "path",
|
||||
"label": "Path"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "thumbnail",
|
||||
"label": "Thumbnail"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "hero",
|
||||
"label": "Hero",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "folder",
|
||||
"label": "Folder"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "file",
|
||||
"label": "File"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "path",
|
||||
"label": "Path"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"key": "delivery",
|
||||
"label": "Delivery",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"key": "others",
|
||||
"label": "Others",
|
||||
"collapsible_key": true,
|
||||
"object_type": {
|
||||
"type": "dict-modifiable",
|
||||
"object_type": "text"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,439 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "publish",
|
||||
"label": "Publish plugins",
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"key": "IntegrateHeroVersion",
|
||||
"label": "IntegrateHeroVersion",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"key": "ExtractJpegEXR",
|
||||
"label": "ExtractJpegEXR",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "ffmpeg_args",
|
||||
"children": [
|
||||
{
|
||||
"type": "list",
|
||||
"object_type": "text",
|
||||
"key": "input",
|
||||
"label": "FFmpeg input arguments"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"object_type": "text",
|
||||
"key": "output",
|
||||
"label": "FFmpeg output arguments"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "ExtractReview",
|
||||
"label": "ExtractReview",
|
||||
"checkbox_key": "enabled",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "profiles",
|
||||
"label": "Profiles",
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"key": "families",
|
||||
"label": "Families",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"key": "hosts",
|
||||
"label": "Hosts",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"key": "outputs",
|
||||
"label": "Output Definitions",
|
||||
"type": "dict-modifiable",
|
||||
"highlight_content": true,
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"key": "ext",
|
||||
"label": "Output extension",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"key": "tags",
|
||||
"label": "Tags",
|
||||
"type": "enum",
|
||||
"multiselection": true,
|
||||
"enum_items": [
|
||||
{
|
||||
"burnin": "Add burnins"
|
||||
},
|
||||
{
|
||||
"ftrackreview": "Add to Ftrack"
|
||||
},
|
||||
{
|
||||
"delete": "Delete output"
|
||||
},
|
||||
{
|
||||
"slate-frame": "Add slate frame"
|
||||
},
|
||||
{
|
||||
"no-handles": "Skip handle frames"
|
||||
},
|
||||
{
|
||||
"sequence": "Output as image sequence"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "ffmpeg_args",
|
||||
"label": "FFmpeg arguments",
|
||||
"type": "dict",
|
||||
"highlight_content": true,
|
||||
"children": [
|
||||
{
|
||||
"key": "video_filters",
|
||||
"label": "Video filters",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"key": "audio_filters",
|
||||
"label": "Audio filters",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"key": "input",
|
||||
"label": "Input arguments",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"key": "output",
|
||||
"label": "Output arguments",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "filter",
|
||||
"label": "Additional output filtering",
|
||||
"type": "dict",
|
||||
"highlight_content": true,
|
||||
"children": [
|
||||
{
|
||||
"key": "families",
|
||||
"label": "Families",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Width and Height must be both set to higher value than 0 else source resolution is used."
|
||||
},
|
||||
{
|
||||
"key": "width",
|
||||
"label": "Output width",
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 100000
|
||||
},
|
||||
{
|
||||
"key": "height",
|
||||
"label": "Output height",
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 100000
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "ExtractBurnin",
|
||||
"label": "ExtractBurnin",
|
||||
"checkbox_key": "enabled",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "options",
|
||||
"label": "Burnin formating options",
|
||||
"children": [
|
||||
{
|
||||
"type": "number",
|
||||
"key": "font_size",
|
||||
"label": "Font size",
|
||||
"minimum": 0
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "opacity",
|
||||
"label": "Font opacity",
|
||||
"decimal": 2,
|
||||
"maximum": 1,
|
||||
"minimum": 0
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "bg_opacity",
|
||||
"label": "Background opacity",
|
||||
"decimal": 2,
|
||||
"maximum": 1,
|
||||
"minimum": 0
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "x_offset",
|
||||
"label": "X Offset"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "y_offset",
|
||||
"label": "Y Offset"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "bg_padding",
|
||||
"label": "Padding aroung text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "profiles",
|
||||
"label": "Profiles",
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"key": "families",
|
||||
"label": "Families",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"key": "hosts",
|
||||
"label": "Hosts",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"key": "burnins",
|
||||
"label": "Burnins",
|
||||
"type": "dict-modifiable",
|
||||
"highlight_content": true,
|
||||
"collapsible": false,
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"key": "TOP_LEFT",
|
||||
"label": "Top Left",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"key": "TOP_CENTERED",
|
||||
"label": "Top Centered",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"key": "TOP_RIGHT",
|
||||
"label": "top Right",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"key": "BOTTOM_LEFT",
|
||||
"label": "Bottom Left",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"key": "BOTTOM_CENTERED",
|
||||
"label": "Bottom Centered",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"key": "BOTTOM_RIGHT",
|
||||
"label": "BottomRight",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "IntegrateAssetNew",
|
||||
"label": "IntegrateAssetNew",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "raw-json",
|
||||
"key": "template_name_profiles",
|
||||
"label": "template_name_profiles"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "ProcessSubmittedJobOnFarm",
|
||||
"label": "ProcessSubmittedJobOnFarm",
|
||||
"checkbox_key": "enabled",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "deadline_department",
|
||||
"label": "Deadline department"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "deadline_pool",
|
||||
"label": "Deadline Pool"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "deadline_group",
|
||||
"label": "Deadline Group"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "deadline_chunk_size",
|
||||
"label": "Deadline Chunk Size"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "deadline_priority",
|
||||
"label": "Deadline Priotity"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "aov_filter",
|
||||
"label": "Reviewable subsets filter",
|
||||
"children": [
|
||||
{
|
||||
"type": "list",
|
||||
"key": "maya",
|
||||
"label": "Maya",
|
||||
"object_type": {
|
||||
"type": "text"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "nuke",
|
||||
"label": "Nuke",
|
||||
"object_type": {
|
||||
"type": "text"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "aftereffects",
|
||||
"label": "After Effects",
|
||||
"object_type": {
|
||||
"type": "text"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "celaction",
|
||||
"label": "Celaction",
|
||||
"object_type": {
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "tools",
|
||||
"label": "Tools",
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "creator",
|
||||
"label": "Creator",
|
||||
"children": [
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"collapsible": true,
|
||||
"key": "families_smart_select",
|
||||
"label": "Families smart select",
|
||||
"object_type": {
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "subset_name_profiles",
|
||||
"label": "Subset name profiles",
|
||||
"use_label_wrap": true,
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"key": "families",
|
||||
"label": "Families",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"key": "hosts",
|
||||
"label": "Hosts",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"key": "tasks",
|
||||
"label": "Task names",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "template",
|
||||
"label": "Template"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "Workfiles",
|
||||
"label": "Workfiles",
|
||||
"children": [
|
||||
{
|
||||
"type": "list",
|
||||
"key": "last_workfile_on_startup",
|
||||
"label": "Open last workfiles on launch",
|
||||
"is_group": true,
|
||||
"use_label_wrap": true,
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"key": "hosts",
|
||||
"label": "Hosts",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"key": "tasks",
|
||||
"label": "Tasks",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"collapsible": true,
|
||||
"key": "sw_folders",
|
||||
"label": "Extra task folders",
|
||||
"is_group": true,
|
||||
"object_type": {
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "create",
|
||||
"label": "Creator plugins",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_create_plugin",
|
||||
"template_data": [
|
||||
{
|
||||
"key": "CreateAnimation",
|
||||
"label": "Create Animation"
|
||||
},
|
||||
{
|
||||
"key": "CreateAss",
|
||||
"label": "Create Ass"
|
||||
},
|
||||
{
|
||||
"key": "CreateAssembly",
|
||||
"label": "Create Assembly"
|
||||
},
|
||||
{
|
||||
"key": "CreateCamera",
|
||||
"label": "Create Camera"
|
||||
},
|
||||
{
|
||||
"key": "CreateLayout",
|
||||
"label": "Create Layout"
|
||||
},
|
||||
{
|
||||
"key": "CreateLook",
|
||||
"label": "Create Look"
|
||||
},
|
||||
{
|
||||
"key": "CreateMayaScene",
|
||||
"label": "Create Maya Scene"
|
||||
},
|
||||
{
|
||||
"key": "CreateModel",
|
||||
"label": "Create Model"
|
||||
},
|
||||
{
|
||||
"key": "CreatePointCache",
|
||||
"label": "Create Cache"
|
||||
},
|
||||
{
|
||||
"key": "CreateRender",
|
||||
"label": "Create Render"
|
||||
},
|
||||
{
|
||||
"key": "CreateRenderSetup",
|
||||
"label": "Create Render Setup"
|
||||
},
|
||||
{
|
||||
"key": "CreateReview",
|
||||
"label": "Create Review"
|
||||
},
|
||||
{
|
||||
"key": "CreateRig",
|
||||
"label": "Create Rig"
|
||||
},
|
||||
{
|
||||
"key": "CreateSetDress",
|
||||
"label": "Create Set Dress"
|
||||
},
|
||||
{
|
||||
"key": "CreateUnrealStaticMesh",
|
||||
"label": "Create Unreal - Static Mesh"
|
||||
},
|
||||
{
|
||||
"key": "CreateVrayProxy",
|
||||
"label": "Create VRay Proxy"
|
||||
},
|
||||
{
|
||||
"key": "CreateVRayScene",
|
||||
"label": "Create VRay Scene"
|
||||
},
|
||||
{
|
||||
"key": "CreateYetiRig",
|
||||
"label": "Create Yeti Rig"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "load",
|
||||
"label": "Loader plugins",
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "colors",
|
||||
"label": "Loaded Subsets Outliner Colors",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_color",
|
||||
"template_data": [
|
||||
{
|
||||
"label": "Model",
|
||||
"name": "model"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_color",
|
||||
"template_data": [
|
||||
{
|
||||
"label": "Rig",
|
||||
"name": "rig"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_color",
|
||||
"template_data": [
|
||||
{
|
||||
"label": "Pointcache",
|
||||
"name": "pointcache"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_color",
|
||||
"template_data": [
|
||||
{
|
||||
"label": "Animation",
|
||||
"name": "animation"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_color",
|
||||
"template_data": [
|
||||
{
|
||||
"label": "Arnold Standin",
|
||||
"name": "ass"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_color",
|
||||
"template_data": [
|
||||
{
|
||||
"label": "Camera",
|
||||
"name": "camera"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_color",
|
||||
"template_data": [
|
||||
{
|
||||
"label": "FBX",
|
||||
"name": "fbx"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_color",
|
||||
"template_data": [
|
||||
{
|
||||
"label": "Maya Scene",
|
||||
"name": "mayaAscii"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_color",
|
||||
"template_data": [
|
||||
{
|
||||
"label": "Set Dress",
|
||||
"name": "setdress"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_color",
|
||||
"template_data": [
|
||||
{
|
||||
"label": "Layout",
|
||||
"name": "layout"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_color",
|
||||
"template_data": [
|
||||
{
|
||||
"label": "VDB Cache",
|
||||
"name": "vdbcache"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_color",
|
||||
"template_data": [
|
||||
{
|
||||
"label": "Vray Proxy",
|
||||
"name": "vrayproxy"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_color",
|
||||
"template_data": [
|
||||
{
|
||||
"label": "Yeti Cache",
|
||||
"name": "yeticache"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_color",
|
||||
"template_data": [
|
||||
{
|
||||
"label": "Yeti Rig",
|
||||
"name": "yetiRig"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,316 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "publish",
|
||||
"label": "Publish plugins",
|
||||
"children": [
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Collectors"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "CollectMayaRender",
|
||||
"label": "Collect Render Layers",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "sync_workfile_version",
|
||||
"label": "Sync render version with workfile"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Validators"
|
||||
},
|
||||
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "ValidateShaderName",
|
||||
"label": "ValidateShaderName",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Shader name regex can use named capture group <b>asset</b> to validate against current asset name.<p><b>Example:</b><br/><code>^.*(?P=<asset>.+)_SHD</code></p>"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "regex",
|
||||
"label": "Validation regex"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "ValidateAttributes",
|
||||
"label": "ValidateAttributes",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "raw-json",
|
||||
"key": "attributes",
|
||||
"label": "Attributes"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "collapsible-wrap",
|
||||
"label": "Model",
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "ValidateModelName",
|
||||
"label": "Validate Model Name",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Path to material file defining list of material names to check. This is material name per line simple text file.<br/>It will be checked against named group <b>shader</b> in your <em>Validation regex</em>.<p>For example: <br/> <code>^.*(?P=<shader>.+)_GEO</code></p>"
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"key": "material_file",
|
||||
"label": "Material File",
|
||||
"multiplatform": true,
|
||||
"multipath": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "regex",
|
||||
"label": "Validation regex"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "ValidateTransformNamingSuffix",
|
||||
"label": "ValidateTransformNamingSuffix",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Validates transform suffix based on the type of its children shapes."
|
||||
},
|
||||
{
|
||||
"type": "raw-json",
|
||||
"key": "SUFFIX_NAMING_TABLE",
|
||||
"label": "Suffix Naming Table"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "ALLOW_IF_NOT_IN_SUFFIX_TABLE",
|
||||
"label": "Allow if suffix not in table"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_publish_plugin",
|
||||
"template_data": [
|
||||
{
|
||||
"key": "ValidateColorSets",
|
||||
"label": "ValidateColorSets"
|
||||
},
|
||||
{
|
||||
"key": "ValidateMeshHasOverlappingUVs",
|
||||
"label": "ValidateMeshHasOverlappingUVs"
|
||||
},
|
||||
{
|
||||
"key": "ValidateMeshArnoldAttributes",
|
||||
"label": "ValidateMeshArnoldAttributes"
|
||||
},
|
||||
{
|
||||
"key": "ValidateMeshShaderConnections",
|
||||
"label": "ValidateMeshShaderConnections"
|
||||
},
|
||||
{
|
||||
"key": "ValidateMeshSingleUVSet",
|
||||
"label": "ValidateMeshSingleUVSet"
|
||||
},
|
||||
{
|
||||
"key": "ValidateMeshHasUVs",
|
||||
"label": "ValidateMeshHasUVs"
|
||||
},
|
||||
{
|
||||
"key": "ValidateMeshLaminaFaces",
|
||||
"label": "ValidateMeshLaminaFaces"
|
||||
},
|
||||
{
|
||||
"key": "ValidateMeshNonManifold",
|
||||
"label": "ValidateMeshNonManifold"
|
||||
},
|
||||
{
|
||||
"key": "ValidateMeshNormalsUnlocked",
|
||||
"label": "ValidateMeshNormalsUnlocked"
|
||||
},
|
||||
{
|
||||
"key": "ValidateMeshUVSetMap1",
|
||||
"label": "ValidateMeshUVSetMap1",
|
||||
"docstring": "Validate model's default uv set exists and is named 'map1'.<br><br>In Maya meshes by default have a uv set named 'map1' that cannot be deleted. It can be renamed, however,<br> introducing some issues with some renderers. As such we ensure the first (default) UV set index is named 'map1'."
|
||||
},
|
||||
{
|
||||
"key": "ValidateMeshVerticesHaveEdges",
|
||||
"label": "ValidateMeshVerticesHaveEdges"
|
||||
},
|
||||
{
|
||||
"key": "ValidateNoAnimation",
|
||||
"label": "ValidateNoAnimation",
|
||||
"docstring": "Ensure no keyframes on nodes in the Instance.<br>Even though a Model would extract without animCurves correctly this avoids getting different <br> output from a model when extracted from a different frame than the first frame. (Might be overly restrictive though)."
|
||||
},
|
||||
{
|
||||
"key": "ValidateNoNamespace",
|
||||
"label": "ValidateNoNamespace"
|
||||
},
|
||||
{
|
||||
"key": "ValidateNoNullTransforms",
|
||||
"label": "ValidateNoNullTransforms"
|
||||
},
|
||||
{
|
||||
"key": "ValidateNoUnknownNodes",
|
||||
"label": "ValidateNoUnknownNodes"
|
||||
},
|
||||
{
|
||||
"key": "ValidateNodeNoGhosting",
|
||||
"label": "ValidateNodeNoGhosting"
|
||||
},
|
||||
{
|
||||
"key": "ValidateShapeDefaultNames",
|
||||
"label": "ValidateShapeDefaultNames"
|
||||
},
|
||||
{
|
||||
"key": "ValidateShapeRenderStats",
|
||||
"label": "ValidateShapeRenderStats"
|
||||
},
|
||||
{
|
||||
"key": "ValidateTransformZero",
|
||||
"label": "ValidateTransformZero"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_publish_plugin",
|
||||
"template_data": [
|
||||
{
|
||||
"key": "ValidateCameraAttributes",
|
||||
"label": "Validate Camera Attributes",
|
||||
"docstring": ""
|
||||
},
|
||||
{
|
||||
"key": "ValidateAssemblyName",
|
||||
"label": "Validate Assembly Name"
|
||||
},
|
||||
{
|
||||
"key": "ValidateAssRelativePaths",
|
||||
"label": "ValidateAssRelativePaths"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Extractors"
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_maya_capture"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "ExtractCameraAlembic",
|
||||
"label": "Extract camera to Alembic",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "List of attributes that will be added to the baked alembic camera. Needs to be written in python list syntax.<p>For example: <br/> <code>[\"attributeName\", \"anotherAttribute\"]</code></p>"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "optional",
|
||||
"label": "Optional"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "active",
|
||||
"label": "Active"
|
||||
},
|
||||
{
|
||||
"type": "raw-json",
|
||||
"key": "bake_attributes",
|
||||
"label": "Bake Attributes",
|
||||
"is_list": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "MayaSubmitDeadline",
|
||||
"label": "Submit maya job to deadline",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "enum",
|
||||
"key": "tile_assembler_plugin",
|
||||
"label": "Tile Assembler Plugin",
|
||||
"multiselection": false,
|
||||
"enum_items": [
|
||||
{
|
||||
"DraftTileAssembler": "Draft Tile Assembler"
|
||||
},
|
||||
{
|
||||
"oiio": "Open Image IO"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "load",
|
||||
"label": "Loader plugins",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_loader_plugin_nuke",
|
||||
"template_data": [
|
||||
{
|
||||
"key": "LoadImage",
|
||||
"label": "Image Loader"
|
||||
},
|
||||
{
|
||||
"key": "LoadMov",
|
||||
"label": "Movie Loader"
|
||||
},
|
||||
{
|
||||
"key": "LoadSequence",
|
||||
"label": "Image Sequence Loader"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "publish",
|
||||
"label": "Publish plugins",
|
||||
"children": [
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Collectors"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "PreCollectNukeInstances",
|
||||
"label": "PreCollectNukeInstances",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "sync_workfile_version",
|
||||
"label": "Sync Version from workfile"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Validators"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"key": "ValidateKnobs",
|
||||
"label": "ValidateKnobs",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "raw-json",
|
||||
"key": "knobs",
|
||||
"label": "Knobs"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_publish_plugin",
|
||||
"template_data": [
|
||||
{
|
||||
"key": "ValidateOutputResolution",
|
||||
"label": "Validate Output Resolution"
|
||||
},
|
||||
{
|
||||
"key": "ValidateGizmo",
|
||||
"label": "Validate Gizmo (Group)"
|
||||
},
|
||||
{
|
||||
"key": "ValidateScript",
|
||||
"label": "Validate script settings"
|
||||
},
|
||||
{
|
||||
"key": "ValidateNukeWriteBoundingBox",
|
||||
"label": "Validate and Write Bounding Box"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Extractors"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"key": "ExtractThumbnail",
|
||||
"label": "ExtractThumbnail",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "raw-json",
|
||||
"key": "nodes",
|
||||
"label": "Nodes"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"key": "ExtractReviewDataLut",
|
||||
"label": "ExtractReviewDataLut",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"key": "ExtractReviewDataMov",
|
||||
"label": "ExtractReviewDataMov",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "viewer_lut_raw",
|
||||
"label": "Viewer LUT raw"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "ExtractSlateFrame",
|
||||
"label": "ExtractSlateFrame",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "viewer_lut_raw",
|
||||
"label": "Viewer LUT raw"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "NukeSubmitDeadline",
|
||||
"label": "NukeSubmitDeadline",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "number",
|
||||
"key": "deadline_priority",
|
||||
"label": "deadline_priority"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "deadline_pool",
|
||||
"label": "deadline_pool"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "deadline_pool_secondary",
|
||||
"label": "deadline_pool_secondary"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "deadline_chunk_size",
|
||||
"label": "deadline_chunk_size"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"type": "dict-modifiable",
|
||||
"collapsible": true,
|
||||
"key": "filters",
|
||||
"label": "Publish GUI Filters",
|
||||
"object_type": {
|
||||
"type": "raw-json",
|
||||
"label": "Plugins"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "workfile_build",
|
||||
"label": "Workfile Build Settings",
|
||||
"children": [
|
||||
{
|
||||
"type": "list",
|
||||
"key": "profiles",
|
||||
"label": "Profiles",
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"key": "tasks",
|
||||
"label": "Tasks",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"key": "current_context",
|
||||
"label": "<b>Current Context</b>",
|
||||
"type": "list",
|
||||
"highlight_content": true,
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"key": "subset_name_filters",
|
||||
"label": "Subset name Filters",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"key": "families",
|
||||
"label": "Families",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"key": "repre_names",
|
||||
"label": "Repre Names",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"key": "loaders",
|
||||
"label": "Loaders",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "linked_assets",
|
||||
"label": "<b>Linked Assets</b>",
|
||||
"type": "list",
|
||||
"highlight_content": true,
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"key": "subset_name_filters",
|
||||
"label": "Subset name Filters",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"key": "families",
|
||||
"label": "Families",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"key": "repre_names",
|
||||
"label": "Repre Names",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"key": "loaders",
|
||||
"label": "Loaders",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
[
|
||||
{
|
||||
"type": "list-strict",
|
||||
"key": "{name}",
|
||||
"label": "{label}:",
|
||||
"object_types": [
|
||||
{
|
||||
"label": "Red",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
},
|
||||
{
|
||||
"label": "Green",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
},
|
||||
{
|
||||
"label": "Blue",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
[
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "{key}",
|
||||
"label": "{label}",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "defaults",
|
||||
"label": "Default Subsets",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
[
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "{key}",
|
||||
"label": "{label}",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "families",
|
||||
"label": "Families",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "representations",
|
||||
"label": "Representations",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "node_name_template",
|
||||
"label": "Node name template"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,541 @@
|
|||
[
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "ExtractPlayblast",
|
||||
"label": "Extract Playblast settings",
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "capture_preset",
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "Codec",
|
||||
"children": [
|
||||
{
|
||||
"type": "label",
|
||||
"label": "<b>Codec</b>"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "compression",
|
||||
"label": "Compression type"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "format",
|
||||
"label": "Data format"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "quality",
|
||||
"label": "Quality",
|
||||
"decimal": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 100
|
||||
},
|
||||
|
||||
{
|
||||
"type": "splitter"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "Display Options",
|
||||
"children": [
|
||||
{
|
||||
"type": "label",
|
||||
"label": "<b>Display Options</b>"
|
||||
},
|
||||
{
|
||||
"type": "list-strict",
|
||||
"key": "background",
|
||||
"label": "Background Color: ",
|
||||
"object_types": [
|
||||
{
|
||||
"label": "Red",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
},
|
||||
{
|
||||
"label": "Green",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
},
|
||||
{
|
||||
"label": "Blue",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "list-strict",
|
||||
"key": "backgroundBottom",
|
||||
"label": "Background Bottom: ",
|
||||
"object_types": [
|
||||
{
|
||||
"label": "Red",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
},
|
||||
{
|
||||
"label": "Green",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
},
|
||||
{
|
||||
"label": "Blue",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "list-strict",
|
||||
"key": "backgroundTop",
|
||||
"label": "Background Top: ",
|
||||
"object_types": [
|
||||
{
|
||||
"label": "Red",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
},
|
||||
{
|
||||
"label": "Green",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
},
|
||||
{
|
||||
"label": "Blue",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "override_display",
|
||||
"label": "Override display options"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "Generic",
|
||||
"children": [
|
||||
{
|
||||
"type": "label",
|
||||
"label": "<b>Generic</b>"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "isolate_view",
|
||||
"label": " Isolate view"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "off_screen",
|
||||
"label": " Off Screen"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "PanZoom",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "pan_zoom",
|
||||
"label": " Pan Zoom"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "Renderer",
|
||||
"children": [
|
||||
{
|
||||
"type": "label",
|
||||
"label": "<b>Renderer</b>"
|
||||
},
|
||||
{
|
||||
"type": "enum",
|
||||
"key": "rendererName",
|
||||
"label": "Renderer name",
|
||||
"enum_items": [
|
||||
{ "vp2Renderer": "Viewport 2.0" }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "Resolution",
|
||||
"children": [
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "<b>Resolution</b>"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "width",
|
||||
"label": " Width",
|
||||
"decimal": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 99999
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "height",
|
||||
"label": "Height",
|
||||
"decimal": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 99999
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "percent",
|
||||
"label": "percent",
|
||||
"decimal": 1,
|
||||
"minimum": 0,
|
||||
"maximum": 200
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "mode",
|
||||
"label": "Mode"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "Viewport Options",
|
||||
"label": "Viewport Options",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "override_viewport_options",
|
||||
"label": "override_viewport_options"
|
||||
},
|
||||
{
|
||||
"type": "enum",
|
||||
"key": "displayLights",
|
||||
"label": "Display Lights",
|
||||
"enum_items": [
|
||||
{ "default": "Default Lighting"},
|
||||
{ "all": "All Lights"},
|
||||
{ "selected": "Selected Lights"},
|
||||
{ "flat": "Flat Lighting"},
|
||||
{ "nolights": "No Lights"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "textureMaxResolution",
|
||||
"label": "Texture Clamp Resolution",
|
||||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "multiSample",
|
||||
"label": "Anti Aliasing Samples",
|
||||
"decimal": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 32
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "shadows",
|
||||
"label": "Display Shadows"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "textures",
|
||||
"label": "Display Textures"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "twoSidedLighting",
|
||||
"label": "Two Sided Lighting"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "ssaoEnable",
|
||||
"label": "Screen Space Ambient Occlusion"
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "cameras",
|
||||
"label": "cameras"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "clipGhosts",
|
||||
"label": "clipGhosts"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "controlVertices",
|
||||
"label": "controlVertices"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "deformers",
|
||||
"label": "deformers"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "dimensions",
|
||||
"label": "dimensions"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "dynamicConstraints",
|
||||
"label": "dynamicConstraints"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "dynamics",
|
||||
"label": "dynamics"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "fluids",
|
||||
"label": "fluids"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "follicles",
|
||||
"label": "follicles"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "gpuCacheDisplayFilter",
|
||||
"label": "gpuCacheDisplayFilter"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "greasePencils",
|
||||
"label": "greasePencils"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "grid",
|
||||
"label": "grid"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "hairSystems",
|
||||
"label": "hairSystems"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "handles",
|
||||
"label": "handles"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "hud",
|
||||
"label": "hud"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "hulls",
|
||||
"label": "hulls"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "ikHandles",
|
||||
"label": "ikHandles"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "imagePlane",
|
||||
"label": "imagePlane"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "joints",
|
||||
"label": "joints"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "lights",
|
||||
"label": "lights"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "locators",
|
||||
"label": "locators"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "manipulators",
|
||||
"label": "manipulators"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "motionTrails",
|
||||
"label": "motionTrails"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "nCloths",
|
||||
"label": "nCloths"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "nParticles",
|
||||
"label": "nParticles"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "nRigids",
|
||||
"label": "nRigids"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "nurbsCurves",
|
||||
"label": "nurbsCurves"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "nurbsSurfaces",
|
||||
"label": "nurbsSurfaces"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "particleInstancers",
|
||||
"label": "particleInstancers"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "pivots",
|
||||
"label": "pivots"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "planes",
|
||||
"label": "planes"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "pluginShapes",
|
||||
"label": "pluginShapes"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "polymeshes",
|
||||
"label": "polymeshes"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "strokes",
|
||||
"label": "strokes"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "subdivSurfaces",
|
||||
"label": "subdivSurfaces"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "Camera Options",
|
||||
"label": "Camera Options",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "displayGateMask",
|
||||
"label": "displayGateMask"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "displayResolution",
|
||||
"label": "displayResolution"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "displayFilmGate",
|
||||
"label": "displayFilmGate"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "displayFieldChart",
|
||||
"label": "displayFieldChart"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "displaySafeAction",
|
||||
"label": "displaySafeAction"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "displaySafeTitle",
|
||||
"label": "displaySafeTitle"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "displayFilmPivot",
|
||||
"label": "displayFilmPivot"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "displayFilmOrigin",
|
||||
"label": "displayFilmOrigin"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "overscan",
|
||||
"label": "overscan",
|
||||
"decimal": 1,
|
||||
"minimum": 0,
|
||||
"maximum": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
[
|
||||
{
|
||||
"__default_values__": {
|
||||
"docstring": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "{key}",
|
||||
"label": "{label}",
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "optional",
|
||||
"label": "Optional"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "active",
|
||||
"label": "Active"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "{docstring}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,495 @@
|
|||
{
|
||||
"key": "example_dict",
|
||||
"label": "Examples",
|
||||
"type": "dict",
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "schema_template_exaples",
|
||||
"label": "Schema template examples",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "example_template",
|
||||
"template_data": {
|
||||
"host_label": "Application 1",
|
||||
"host_name": "app_1",
|
||||
"multipath_executables": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "example_template",
|
||||
"template_data": {
|
||||
"host_label": "Application 2",
|
||||
"host_name": "app_2"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "env_group_test",
|
||||
"label": "EnvGroup Test",
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"key": "key_to_store_in_system_settings",
|
||||
"label": "Testing environment group",
|
||||
"type": "raw-json",
|
||||
"env_group_key": "test_group"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "dict_wrapper",
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"type": "enum",
|
||||
"key": "test_enum_singleselection",
|
||||
"label": "Enum Single Selection",
|
||||
"enum_items": [
|
||||
{ "value_1": "Label 1" },
|
||||
{ "value_2": "Label 2" },
|
||||
{ "value_3": "Label 3" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "enum",
|
||||
"key": "test_enum_multiselection",
|
||||
"label": "Enum Multi Selection",
|
||||
"multiselection": true,
|
||||
"enum_items": [
|
||||
{ "value_1": "Label 1" },
|
||||
{ "value_2": "Label 2" },
|
||||
{ "value_3": "Label 3" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "bool",
|
||||
"label": "Boolean checkbox"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "NOTE: This is label"
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "integer",
|
||||
"label": "Integer",
|
||||
"decimal": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 10
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "float",
|
||||
"label": "Float (2 decimals)",
|
||||
"decimal": 2,
|
||||
"minimum": -10,
|
||||
"maximum": -5
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "singleline_text",
|
||||
"label": "Singleline text"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "multiline_text",
|
||||
"label": "Multiline text",
|
||||
"multiline": true
|
||||
},
|
||||
{
|
||||
"type": "raw-json",
|
||||
"key": "raw_json",
|
||||
"label": "Raw json input"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "list_item_of_multiline_texts",
|
||||
"label": "List of multiline texts",
|
||||
"object_type": {
|
||||
"type": "text",
|
||||
"multiline": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "list_item_of_floats",
|
||||
"label": "List of floats",
|
||||
"object_type": {
|
||||
"type": "number",
|
||||
"decimal": 3,
|
||||
"minimum": 1000,
|
||||
"maximum": 2000
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"key": "modifiable_dict_of_integers",
|
||||
"label": "Modifiable dict of integers",
|
||||
"object_type": {
|
||||
"type": "number",
|
||||
"decimal": 0,
|
||||
"minimum": 10,
|
||||
"maximum": 100
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"key": "modifiable_dict_with_required_keys",
|
||||
"label": "Modifiable dict with required keys",
|
||||
"required_keys": [
|
||||
"key_1",
|
||||
"key_2"
|
||||
],
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"type": "list-strict",
|
||||
"key": "strict_list_labels_horizontal",
|
||||
"label": "StrictList-labels-horizontal (color)",
|
||||
"object_types": [
|
||||
{
|
||||
"label": "Red",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 255,
|
||||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"label": "Green",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 255,
|
||||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"label": "Blue",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 255,
|
||||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"label": "Alpha",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 6
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "list-strict",
|
||||
"key": "strict_list_labels_vertical",
|
||||
"label": "StrictList-labels-vertical (color)",
|
||||
"horizontal": false,
|
||||
"object_types": [
|
||||
{
|
||||
"label": "Red",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 255,
|
||||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"label": "Green",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 255,
|
||||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"label": "Blue",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 255,
|
||||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"label": "Alpha",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 6
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "list-strict",
|
||||
"key": "strict_list_nolabels_horizontal",
|
||||
"label": "StrictList-nolabels-horizontal (color)",
|
||||
"object_types": [
|
||||
{
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 255,
|
||||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 255,
|
||||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 255,
|
||||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 6
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "list-strict",
|
||||
"key": "strict_list_nolabels_vertical",
|
||||
"label": "StrictList-nolabels-vertical (color)",
|
||||
"horizontal": false,
|
||||
"object_types": [
|
||||
{
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 255,
|
||||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 255,
|
||||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 255,
|
||||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 6
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "dict_item",
|
||||
"label": "DictItem in List",
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"key": "families",
|
||||
"label": "Families",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"key": "hosts",
|
||||
"label": "Hosts",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"key": "single_path_input",
|
||||
"label": "Single path input",
|
||||
"multiplatform": false,
|
||||
"multipath": false
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"key": "multi_path_input",
|
||||
"label": "Multi path input",
|
||||
"multiplatform": false,
|
||||
"multipath": true
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"key": "single_os_specific_path_input",
|
||||
"label": "Single OS specific path input",
|
||||
"multiplatform": true,
|
||||
"multipath": false
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"key": "multi_os_specific_path_input",
|
||||
"label": "Multi OS specific path input",
|
||||
"multiplatform": true,
|
||||
"multipath": true
|
||||
},
|
||||
{
|
||||
"key": "collapsible",
|
||||
"type": "dict",
|
||||
"label": "collapsible dictionary",
|
||||
"collapsible": true,
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "_nothing",
|
||||
"label": "Exmaple input"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "collapsible_expanded",
|
||||
"type": "dict",
|
||||
"label": "collapsible dictionary, expanded on creation",
|
||||
"collapsible": true,
|
||||
"collapsed": false,
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "_nothing",
|
||||
"label": "Exmaple input"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "not_collapsible",
|
||||
"type": "dict",
|
||||
"label": "Not collapsible",
|
||||
"collapsible": false,
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "_nothing",
|
||||
"label": "Exmaple input"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "nested_dict_lvl1",
|
||||
"type": "dict",
|
||||
"label": "Nested dictionary (level 1)",
|
||||
"children": [
|
||||
{
|
||||
"key": "nested_dict_lvl2",
|
||||
"type": "dict",
|
||||
"label": "Nested dictionary (level 2)",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"key": "nested_dict_lvl3",
|
||||
"type": "dict",
|
||||
"label": "Nested dictionary (level 3)",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "_nothing",
|
||||
"label": "Exmaple input"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "nested_dict_lvl3_2",
|
||||
"type": "dict",
|
||||
"label": "Nested dictionary (level 3) (2)",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "_nothing",
|
||||
"label": "Exmaple input"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "_nothing2",
|
||||
"label": "Exmaple input 2"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "form_examples",
|
||||
"type": "dict",
|
||||
"label": "Form examples",
|
||||
"children": [
|
||||
{
|
||||
"key": "inputs_without_form_example",
|
||||
"type": "dict",
|
||||
"label": "Inputs without form",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "_nothing_1",
|
||||
"label": "Example label"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "_nothing_2",
|
||||
"label": "Example label ####"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "_nothing_3",
|
||||
"label": "Example label ########"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "inputs_with_form_example",
|
||||
"type": "dict",
|
||||
"label": "Inputs with form",
|
||||
"children": [
|
||||
{
|
||||
"type": "form",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "_nothing_1",
|
||||
"label": "Example label"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "_nothing_2",
|
||||
"label": "Example label ####"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "_nothing_3",
|
||||
"label": "Example label ########"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "collapsible-wrap",
|
||||
"label": "Collapsible Wrapper without key",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "_example_input_collapsible",
|
||||
"label": "Example input in collapsible wrapper"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
[
|
||||
{
|
||||
"__default_values__": {
|
||||
"multipath_executables": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "raw-json",
|
||||
"label": "{host_label} Environments",
|
||||
"key": "{host_name}_environments",
|
||||
"env_group_key": "{host_name}"
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"key": "{host_name}_executables",
|
||||
"label": "{host_label} - Full paths to executables",
|
||||
"multiplatform": "{multipath_executables}",
|
||||
"multipath": true
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "aftereffects",
|
||||
"label": "Adobe AfterEffects",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_unchangables"
|
||||
},
|
||||
{
|
||||
"key": "environment",
|
||||
"label": "Environment",
|
||||
"type": "raw-json"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "variants",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_variant",
|
||||
"template_data": [
|
||||
{
|
||||
"app_variant_label": "2020",
|
||||
"app_variant": "2020"
|
||||
},
|
||||
{
|
||||
"app_variant_label": "2021",
|
||||
"app_variant": "2021"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "blender",
|
||||
"label": "Blender",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_unchangables"
|
||||
},
|
||||
{
|
||||
"key": "environment",
|
||||
"label": "Environment",
|
||||
"type": "raw-json"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "variants",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_variant",
|
||||
"template_data": [
|
||||
{
|
||||
"app_variant_label": "2.83",
|
||||
"app_variant": "2-83"
|
||||
},
|
||||
{
|
||||
"app_variant_label": "2.90",
|
||||
"app_variant": "2-90"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "celaction",
|
||||
"label": "CelAction2D",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_unchangables"
|
||||
},
|
||||
{
|
||||
"key": "environment",
|
||||
"label": "Environment",
|
||||
"type": "raw-json"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "variants",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_variant",
|
||||
"template_data": [
|
||||
{
|
||||
"app_variant_label": "Local",
|
||||
"app_variant": "local"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "djvview",
|
||||
"label": "DJV View",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_unchangables"
|
||||
},
|
||||
{
|
||||
"key": "environment",
|
||||
"label": "Environment",
|
||||
"type": "raw-json"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "variants",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_variant",
|
||||
"template_data": {
|
||||
"app_variant_label": "1.1",
|
||||
"app_variant": "1-1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "fusion",
|
||||
"label": "Blackmagic Fusion",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_unchangables"
|
||||
},
|
||||
{
|
||||
"key": "environment",
|
||||
"label": "Environment",
|
||||
"type": "raw-json"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "variants",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_variant",
|
||||
"template_data": [
|
||||
{
|
||||
"app_variant_label": "16",
|
||||
"app_variant": "16"
|
||||
},
|
||||
{
|
||||
"app_variant_label": "9",
|
||||
"app_variant": "9"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "harmony",
|
||||
"label": "Toon Boom Harmony",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_unchangables"
|
||||
},
|
||||
{
|
||||
"key": "environment",
|
||||
"label": "Environment",
|
||||
"type": "raw-json"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "variants",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_variant",
|
||||
"template_data": [
|
||||
{
|
||||
"app_variant_label": "20",
|
||||
"app_variant": "20"
|
||||
},
|
||||
{
|
||||
"app_variant_label": "17",
|
||||
"app_variant": "17"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "houdini",
|
||||
"label": "SideFX Houdini",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_unchangables"
|
||||
},
|
||||
{
|
||||
"key": "environment",
|
||||
"label": "Environment",
|
||||
"type": "raw-json"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "variants",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_variant",
|
||||
"template_data": [
|
||||
{
|
||||
"app_variant_label": "18.5",
|
||||
"app_variant": "18-5"
|
||||
},
|
||||
{
|
||||
"app_variant_label": "18",
|
||||
"app_variant": "18"
|
||||
},
|
||||
{
|
||||
"app_variant_label": "17",
|
||||
"app_variant": "17"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "maya",
|
||||
"label": "Autodesk Maya",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_unchangables"
|
||||
},
|
||||
{
|
||||
"key": "environment",
|
||||
"label": "Environment",
|
||||
"type": "raw-json"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "variants",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_variant",
|
||||
"template_data": [
|
||||
{
|
||||
"app_variant_label": "2020",
|
||||
"app_variant": "2020"
|
||||
},
|
||||
{
|
||||
"app_variant_label": "2019",
|
||||
"app_variant": "2019"
|
||||
},
|
||||
{
|
||||
"app_variant_label": "2018",
|
||||
"app_variant": "2018"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "mayabatch",
|
||||
"label": "Autodesk Maya Batch",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_unchangables"
|
||||
},
|
||||
{
|
||||
"key": "environment",
|
||||
"label": "Environment",
|
||||
"type": "raw-json"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "variants",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_variant",
|
||||
"template_data": [
|
||||
{
|
||||
"app_variant_label": "2020",
|
||||
"app_variant": "2020"
|
||||
},
|
||||
{
|
||||
"app_variant_label": "2019",
|
||||
"app_variant": "2019"
|
||||
},
|
||||
{
|
||||
"app_variant_label": "2018",
|
||||
"app_variant": "2018"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "photoshop",
|
||||
"label": "Adobe Photoshop",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_unchangables"
|
||||
},
|
||||
{
|
||||
"key": "environment",
|
||||
"label": "Environment",
|
||||
"type": "raw-json"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "variants",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_variant",
|
||||
"template_data": [
|
||||
{
|
||||
"app_variant_label": "2020",
|
||||
"app_variant": "2020"
|
||||
},
|
||||
{
|
||||
"app_variant_label": "2021",
|
||||
"app_variant": "2021"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "resolve",
|
||||
"label": "Blackmagic DaVinci Resolve",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_unchangables"
|
||||
},
|
||||
{
|
||||
"key": "environment",
|
||||
"label": "Environment",
|
||||
"type": "raw-json"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "variants",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_variant",
|
||||
"template_data": [
|
||||
{
|
||||
"app_variant_label": "16",
|
||||
"app_variant": "16"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "shell",
|
||||
"label": "Shell",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"key": "environment",
|
||||
"label": "Environment",
|
||||
"type": "raw-json"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "variants",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_variant",
|
||||
"template_data": [
|
||||
{
|
||||
"app_variant": "python_3-7",
|
||||
"app_variant_label": "Python 3.7"
|
||||
},
|
||||
{
|
||||
"app_variant": "python_2-7",
|
||||
"app_variant_label": "Python 2.7"
|
||||
},
|
||||
{
|
||||
"app_variant": "terminal",
|
||||
"app_variant_label": "Terminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "tvpaint",
|
||||
"label": "TVPaint",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_unchangables"
|
||||
},
|
||||
{
|
||||
"key": "environment",
|
||||
"label": "Environment",
|
||||
"type": "raw-json"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "variants",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_variant",
|
||||
"template_data": [
|
||||
{
|
||||
"app_variant_label": "Animation 11 (64bits)",
|
||||
"app_variant": "animation_11-64bits"
|
||||
},
|
||||
{
|
||||
"app_variant_label": "Animation 11 (32bits)",
|
||||
"app_variant": "animation_11-32bits"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "unreal",
|
||||
"label": "Unreal Editor",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_unchangables"
|
||||
},
|
||||
{
|
||||
"key": "environment",
|
||||
"label": "Environment",
|
||||
"type": "raw-json"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "variants",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_variant",
|
||||
"template_data": [
|
||||
{
|
||||
"app_variant": "4-24",
|
||||
"app_variant_label": "4.24"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
[
|
||||
{
|
||||
"type": "text",
|
||||
"key": "label",
|
||||
"label": "Label",
|
||||
"placeholder": "Host label (without any version)",
|
||||
"roles": ["developer"]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "icon",
|
||||
"label": "Icon",
|
||||
"placeholder": "Host icon path template",
|
||||
"roles": ["developer"]
|
||||
},
|
||||
{
|
||||
"type": "enum",
|
||||
"key": "host_name",
|
||||
"label": "Host implementation",
|
||||
"enum_items": [
|
||||
{ "": "< without host >" },
|
||||
{ "aftereffects": "aftereffects" },
|
||||
{ "blender": "blender" },
|
||||
{ "celaction": "celaction" },
|
||||
{ "fusion": "fusion" },
|
||||
{ "harmony": "harmony" },
|
||||
{ "hiero": "hiero" },
|
||||
{ "houdini": "houdini" },
|
||||
{ "maya": "maya" },
|
||||
{ "nuke": "nuke" },
|
||||
{ "photoshop": "photoshop" },
|
||||
{ "resolve": "resolve" },
|
||||
{ "tvpaint": "tvpaint" },
|
||||
{ "unreal": "unreal" }
|
||||
],
|
||||
"roles": ["developer"]
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
[
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "{app_variant}",
|
||||
"label": "{app_variant_label}",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "variant_label",
|
||||
"label": "Variant label",
|
||||
"placeholder": "Only \"Label\" is used if not filled."
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"key": "executables",
|
||||
"label": "Executables",
|
||||
"multiplatform": true,
|
||||
"multipath": true
|
||||
},
|
||||
{
|
||||
"type":"separator"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "arguments",
|
||||
"label": "Arguments",
|
||||
"use_label_wrap": false,
|
||||
"children": [
|
||||
{
|
||||
"key": "windows",
|
||||
"label": "Windows",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"key": "darwin",
|
||||
"label": "MacOS",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"key": "linux",
|
||||
"label": "Linux",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "environment",
|
||||
"label": "Environment",
|
||||
"type": "raw-json"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
[
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "{nuke_type}",
|
||||
"label": "Foundry {nuke_label}",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_unchangables"
|
||||
},
|
||||
{
|
||||
"key": "environment",
|
||||
"label": "Environment",
|
||||
"type": "raw-json"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "variants",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_host_variant",
|
||||
"template_data": [
|
||||
{
|
||||
"app_variant": "12-2",
|
||||
"app_variant_label": "12.2"
|
||||
},
|
||||
{
|
||||
"app_variant": "12-0",
|
||||
"app_variant_label": "12.0"
|
||||
},
|
||||
{
|
||||
"app_variant": "11-3",
|
||||
"app_variant_label": "11.3"
|
||||
},
|
||||
{
|
||||
"app_variant": "11-2",
|
||||
"app_variant_label": "11.2"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "ftrack",
|
||||
"label": "Ftrack",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "ftrack_server",
|
||||
"label": "Server"
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Additional Ftrack paths"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "ftrack_actions_path",
|
||||
"label": "Action paths",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"key": "ftrack_events_path",
|
||||
"label": "Event paths",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"key": "intent",
|
||||
"type": "dict",
|
||||
"label": "Intent",
|
||||
"collapsible_key": true,
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Intent"
|
||||
},
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"object_type": "text",
|
||||
"key": "items"
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"key": "default",
|
||||
"type": "text",
|
||||
"label": "Default Intent"
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "custom_attributes",
|
||||
"label": "Custom Attributes",
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "show",
|
||||
"label": "Project Custom attributes",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_custom_attribute",
|
||||
"template_data": [
|
||||
{
|
||||
"key": "avalon_auto_sync"
|
||||
},
|
||||
{
|
||||
"key": "library_project"
|
||||
},
|
||||
{
|
||||
"key": "applications"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "is_hierarchical",
|
||||
"label": "Hierarchical Attributes",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_custom_attribute",
|
||||
"template_data": [
|
||||
{
|
||||
"key": "tools_env"
|
||||
},
|
||||
{
|
||||
"key": "avalon_mongo_id"
|
||||
},
|
||||
{
|
||||
"key": "fps"
|
||||
},
|
||||
{
|
||||
"key": "frameStart"
|
||||
},
|
||||
{
|
||||
"key": "frameEnd"
|
||||
},
|
||||
{
|
||||
"key": "clipIn"
|
||||
},
|
||||
{
|
||||
"key": "clipOut"
|
||||
},
|
||||
{
|
||||
"key": "handleStart"
|
||||
},
|
||||
{
|
||||
"key": "handleEnd"
|
||||
},
|
||||
{
|
||||
"key": "resolutionWidth"
|
||||
},
|
||||
{
|
||||
"key": "resolutionHeight"
|
||||
},
|
||||
{
|
||||
"key": "pixelAspect"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
[
|
||||
{
|
||||
"key": "{key}",
|
||||
"label": "{key}",
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"key": "write_security_roles",
|
||||
"label": "Write roles",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
},
|
||||
{
|
||||
"key": "read_security_roles",
|
||||
"label": "Read roles",
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
{
|
||||
"key": "applications",
|
||||
"type": "dict",
|
||||
"label": "Applications",
|
||||
"collapsible": true,
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_maya"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_mayabatch"
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_nuke",
|
||||
"template_data": {
|
||||
"nuke_type": "nuke",
|
||||
"nuke_label": "Nuke"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_nuke",
|
||||
"template_data": {
|
||||
"nuke_type": "nukex",
|
||||
"nuke_label": "Nuke X"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_nuke",
|
||||
"template_data": {
|
||||
"nuke_type": "nukestudio",
|
||||
"nuke_label": "Nuke Studio"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_nuke",
|
||||
"template_data": {
|
||||
"nuke_type": "hiero",
|
||||
"nuke_label": "Hiero"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_fusion"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_resolve"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_houdini"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_blender"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_harmony"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_tvpaint"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_photoshop"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_aftereffects"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_celaction"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_unreal"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_shell"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_djv"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"key": "general",
|
||||
"type": "dict",
|
||||
"label": "General",
|
||||
"collapsible": true,
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"key": "studio_name",
|
||||
"type": "text",
|
||||
"label": "Studio Name"
|
||||
},
|
||||
{
|
||||
"key": "studio_code",
|
||||
"type": "text",
|
||||
"label": "Studio Short Code"
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"key": "environment",
|
||||
"label": "Environment",
|
||||
"type": "raw-json",
|
||||
"env_group_key": "global"
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"key": "openpype_path",
|
||||
"label": "Versions Repository",
|
||||
"multiplatform": true,
|
||||
"multipath": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"key": "system",
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_general"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_modules"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_applications"
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_tools"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
{
|
||||
"key": "modules",
|
||||
"type": "dict",
|
||||
"label": "Modules",
|
||||
"collapsible": true,
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "avalon",
|
||||
"label": "Avalon",
|
||||
"collapsible": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "number",
|
||||
"key": "AVALON_TIMEOUT",
|
||||
"minimum": 0,
|
||||
"label": "Avalon Mongo Timeout (ms)"
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"label": "Thumbnail Storage Location",
|
||||
"key": "AVALON_THUMBNAIL_ROOT",
|
||||
"multiplatform": true,
|
||||
"multipath": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "schema",
|
||||
"name": "schema_ftrack"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "timers_manager",
|
||||
"label": "Timers Manager",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"decimal": 2,
|
||||
"key": "full_time",
|
||||
"label": "Max idle time"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"decimal": 2,
|
||||
"key": "message_time",
|
||||
"label": "When dialog will show"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "clockify",
|
||||
"label": "Clockify",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "workspace_name",
|
||||
"label": "Workspace name"
|
||||
}
|
||||
]
|
||||
}, {
|
||||
"type": "dict",
|
||||
"key": "sync_server",
|
||||
"label": "Sync Server",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
}]
|
||||
},{
|
||||
"type": "dict",
|
||||
"key": "deadline",
|
||||
"label": "Deadline",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "DEADLINE_REST_URL",
|
||||
"label": "Deadline Resl URL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "muster",
|
||||
"label": "Muster",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "MUSTER_REST_URL",
|
||||
"label": "Muster Rest URL"
|
||||
},
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"object_type": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 300
|
||||
},
|
||||
"is_group": true,
|
||||
"key": "templates_mapping",
|
||||
"label": "Templates mapping",
|
||||
"is_file": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "log_viewer",
|
||||
"label": "Logging",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "user",
|
||||
"label": "User setting",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "standalonepublish_tool",
|
||||
"label": "Standalone Publish",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "idle_manager",
|
||||
"label": "Idle Manager",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"key": "tools",
|
||||
"collapsible": true,
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"label": "Tools",
|
||||
"key": "tool_groups",
|
||||
"collapsible_key": true,
|
||||
"object_type": {
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"key": "environment",
|
||||
"label": "Environments",
|
||||
"type": "raw-json"
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"key": "variants",
|
||||
"collapsible_key": true,
|
||||
"object_type": {
|
||||
"type": "raw-json"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
603
openpype/settings/handlers.py
Normal file
603
openpype/settings/handlers.py
Normal file
|
|
@ -0,0 +1,603 @@
|
|||
import os
|
||||
import json
|
||||
import copy
|
||||
import logging
|
||||
import collections
|
||||
import datetime
|
||||
from abc import ABCMeta, abstractmethod
|
||||
import six
|
||||
import openpype
|
||||
from .constants import (
|
||||
GLOBAL_SETTINGS_KEY,
|
||||
SYSTEM_SETTINGS_KEY,
|
||||
PROJECT_SETTINGS_KEY,
|
||||
PROJECT_ANATOMY_KEY,
|
||||
LOCAL_SETTING_KEY
|
||||
)
|
||||
from .lib import load_json_file
|
||||
|
||||
JSON_EXC = getattr(json.decoder, "JSONDecodeError", ValueError)
|
||||
|
||||
|
||||
@six.add_metaclass(ABCMeta)
|
||||
class SettingsHandler:
|
||||
@abstractmethod
|
||||
def save_studio_settings(self, data):
|
||||
"""Save studio overrides of system settings.
|
||||
|
||||
Do not use to store whole system settings data with defaults but only
|
||||
it's overrides with metadata defining how overrides should be applied
|
||||
in load function. For loading should be used function
|
||||
`studio_system_settings`.
|
||||
|
||||
Args:
|
||||
data(dict): Data of studio overrides with override metadata.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def save_project_settings(self, project_name, overrides):
|
||||
"""Save studio overrides of project settings.
|
||||
|
||||
Data are saved for specific project or as defaults for all projects.
|
||||
|
||||
Do not use to store whole project settings data with defaults but only
|
||||
it's overrides with metadata defining how overrides should be applied
|
||||
in load function. For loading should be used function
|
||||
`get_studio_project_settings_overrides` for global project settings
|
||||
and `get_project_settings_overrides` for project specific settings.
|
||||
|
||||
Args:
|
||||
project_name(str, null): Project name for which overrides are
|
||||
or None for global settings.
|
||||
data(dict): Data of project overrides with override metadata.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def save_project_anatomy(self, project_name, anatomy_data):
|
||||
"""Save studio overrides of project anatomy data.
|
||||
|
||||
Args:
|
||||
project_name(str, null): Project name for which overrides are
|
||||
or None for global settings.
|
||||
data(dict): Data of project overrides with override metadata.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_studio_system_settings_overrides(self):
|
||||
"""Studio overrides of system settings."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_studio_project_settings_overrides(self):
|
||||
"""Studio overrides of default project settings."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_studio_project_anatomy_overrides(self):
|
||||
"""Studio overrides of default project anatomy data."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_project_settings_overrides(self, project_name):
|
||||
"""Studio overrides of project settings for specific project.
|
||||
|
||||
Args:
|
||||
project_name(str): Name of project for which data should be loaded.
|
||||
|
||||
Returns:
|
||||
dict: Only overrides for entered project, may be empty dictionary.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_project_anatomy_overrides(self, project_name):
|
||||
"""Studio overrides of project anatomy for specific project.
|
||||
|
||||
Args:
|
||||
project_name(str): Name of project for which data should be loaded.
|
||||
|
||||
Returns:
|
||||
dict: Only overrides for entered project, may be empty dictionary.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
@six.add_metaclass(ABCMeta)
|
||||
class LocalSettingsHandler:
|
||||
"""Handler that should handle about storing and loading of local settings.
|
||||
|
||||
Local settings are "workstation" specific modifications that modify how
|
||||
system and project settings look on the workstation and only there.
|
||||
"""
|
||||
@abstractmethod
|
||||
def save_local_settings(self, data):
|
||||
"""Save local data of local settings.
|
||||
|
||||
Args:
|
||||
data(dict): Data of local data with override metadata.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_local_settings(self):
|
||||
"""Studio overrides of system settings."""
|
||||
pass
|
||||
|
||||
|
||||
class CacheValues:
|
||||
cache_lifetime = 10
|
||||
|
||||
def __init__(self):
|
||||
self.data = None
|
||||
self.creation_time = None
|
||||
|
||||
def data_copy(self):
|
||||
if not self.data:
|
||||
return {}
|
||||
return copy.deepcopy(self.data)
|
||||
|
||||
def update_data(self, data):
|
||||
self.data = data
|
||||
self.creation_time = datetime.datetime.now()
|
||||
|
||||
def update_from_document(self, document):
|
||||
data = {}
|
||||
if document:
|
||||
if "data" in document:
|
||||
data = document["data"]
|
||||
elif "value" in document:
|
||||
value = document["value"]
|
||||
if value:
|
||||
data = json.loads(value)
|
||||
self.data = data
|
||||
|
||||
def to_json_string(self):
|
||||
return json.dumps(self.data or {})
|
||||
|
||||
@property
|
||||
def is_outdated(self):
|
||||
if self.creation_time is None:
|
||||
return True
|
||||
delta = (datetime.datetime.now() - self.creation_time).seconds
|
||||
return delta > self.cache_lifetime
|
||||
|
||||
|
||||
class MongoSettingsHandler(SettingsHandler):
|
||||
"""Settings handler that use mongo for storing and loading of settings."""
|
||||
|
||||
def __init__(self):
|
||||
# Get mongo connection
|
||||
from openpype.lib import OpenPypeMongoConnection
|
||||
from avalon.api import AvalonMongoDB
|
||||
|
||||
settings_collection = OpenPypeMongoConnection.get_mongo_client()
|
||||
|
||||
self._anatomy_keys = None
|
||||
self._attribute_keys = None
|
||||
# TODO prepare version of pype
|
||||
# - pype version should define how are settings saved and loaded
|
||||
|
||||
database_name = os.environ["OPENPYPE_DATABASE_NAME"]
|
||||
# TODO modify to not use hardcoded keys
|
||||
collection_name = "settings"
|
||||
|
||||
self.settings_collection = settings_collection
|
||||
|
||||
self.database_name = database_name
|
||||
self.collection_name = collection_name
|
||||
|
||||
self.collection = settings_collection[database_name][collection_name]
|
||||
self.avalon_db = AvalonMongoDB()
|
||||
|
||||
self.system_settings_cache = CacheValues()
|
||||
self.project_settings_cache = collections.defaultdict(CacheValues)
|
||||
self.project_anatomy_cache = collections.defaultdict(CacheValues)
|
||||
|
||||
def _prepare_project_settings_keys(self):
|
||||
from .entities import ProjectSettings
|
||||
# Prepare anatomy keys and attribute keys
|
||||
# NOTE this is cached on first import
|
||||
# - keys may change only on schema change which should not happen
|
||||
# during production
|
||||
project_settings_root = ProjectSettings(
|
||||
reset=False, change_state=False
|
||||
)
|
||||
anatomy_entity = project_settings_root["project_anatomy"]
|
||||
anatomy_keys = set(anatomy_entity.keys())
|
||||
anatomy_keys.remove("attributes")
|
||||
attribute_keys = set(anatomy_entity["attributes"].keys())
|
||||
|
||||
self._anatomy_keys = anatomy_keys
|
||||
self._attribute_keys = attribute_keys
|
||||
|
||||
@property
|
||||
def anatomy_keys(self):
|
||||
if self._anatomy_keys is None:
|
||||
self._prepare_project_settings_keys()
|
||||
return self._anatomy_keys
|
||||
|
||||
@property
|
||||
def attribute_keys(self):
|
||||
if self._attribute_keys is None:
|
||||
self._prepare_project_settings_keys()
|
||||
return self._attribute_keys
|
||||
|
||||
def _prepare_global_settings(self, data):
|
||||
output = {}
|
||||
# Add "openpype_path" key to global settings if is set
|
||||
if "general" in data and "openpype_path" in data["general"]:
|
||||
output["openpype_path"] = data["general"]["openpype_path"]
|
||||
return output
|
||||
|
||||
def save_studio_settings(self, data):
|
||||
"""Save studio overrides of system settings.
|
||||
|
||||
Do not use to store whole system settings data with defaults but only
|
||||
it's overrides with metadata defining how overrides should be applied
|
||||
in load function. For loading should be used function
|
||||
`studio_system_settings`.
|
||||
|
||||
Args:
|
||||
data(dict): Data of studio overrides with override metadata.
|
||||
"""
|
||||
# Store system settings
|
||||
self.system_settings_cache.update_data(data)
|
||||
self.collection.replace_one(
|
||||
{
|
||||
"type": SYSTEM_SETTINGS_KEY
|
||||
},
|
||||
{
|
||||
"type": SYSTEM_SETTINGS_KEY,
|
||||
"data": self.system_settings_cache.data
|
||||
},
|
||||
upsert=True
|
||||
)
|
||||
|
||||
# Get global settings from system settings
|
||||
global_settings = self._prepare_global_settings(
|
||||
self.system_settings_cache.data
|
||||
)
|
||||
# Store global settings
|
||||
self.collection.replace_one(
|
||||
{
|
||||
"type": GLOBAL_SETTINGS_KEY
|
||||
},
|
||||
{
|
||||
"type": GLOBAL_SETTINGS_KEY,
|
||||
"data": global_settings
|
||||
},
|
||||
upsert=True
|
||||
)
|
||||
|
||||
def save_project_settings(self, project_name, overrides):
|
||||
"""Save studio overrides of project settings.
|
||||
|
||||
Data are saved for specific project or as defaults for all projects.
|
||||
|
||||
Do not use to store whole project settings data with defaults but only
|
||||
it's overrides with metadata defining how overrides should be applied
|
||||
in load function. For loading should be used function
|
||||
`get_studio_project_settings_overrides` for global project settings
|
||||
and `get_project_settings_overrides` for project specific settings.
|
||||
|
||||
Args:
|
||||
project_name(str, null): Project name for which overrides are
|
||||
or None for global settings.
|
||||
data(dict): Data of project overrides with override metadata.
|
||||
"""
|
||||
data_cache = self.project_settings_cache[project_name]
|
||||
data_cache.update_data(overrides)
|
||||
|
||||
self._save_project_data(
|
||||
project_name, PROJECT_SETTINGS_KEY, data_cache
|
||||
)
|
||||
|
||||
def save_project_anatomy(self, project_name, anatomy_data):
|
||||
"""Save studio overrides of project anatomy data.
|
||||
|
||||
Args:
|
||||
project_name(str, null): Project name for which overrides are
|
||||
or None for global settings.
|
||||
data(dict): Data of project overrides with override metadata.
|
||||
"""
|
||||
data_cache = self.project_anatomy_cache[project_name]
|
||||
data_cache.update_data(anatomy_data)
|
||||
|
||||
if project_name is not None:
|
||||
self._save_project_anatomy_data(project_name, data_cache)
|
||||
|
||||
else:
|
||||
self._save_project_data(
|
||||
project_name, PROJECT_ANATOMY_KEY, data_cache
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def prepare_mongo_update_dict(cls, in_data):
|
||||
data = {}
|
||||
for key, value in in_data.items():
|
||||
if not isinstance(value, dict):
|
||||
data[key] = value
|
||||
continue
|
||||
|
||||
new_value = cls.prepare_mongo_update_dict(value)
|
||||
for _key, _value in new_value.items():
|
||||
new_key = ".".join((key, _key))
|
||||
data[new_key] = _value
|
||||
|
||||
return data
|
||||
|
||||
def _save_project_anatomy_data(self, project_name, data_cache):
|
||||
# Create copy of data as they will be modified during save
|
||||
new_data = data_cache.data_copy()
|
||||
|
||||
# Prepare avalon project document
|
||||
collection = self.avalon_db.database[project_name]
|
||||
project_doc = collection.find_one({
|
||||
"type": "project"
|
||||
})
|
||||
if not project_doc:
|
||||
raise ValueError((
|
||||
"Project document of project \"{}\" does not exists."
|
||||
" Create project first."
|
||||
).format(project_name))
|
||||
|
||||
# Project's data
|
||||
update_dict_data = {}
|
||||
project_doc_data = project_doc.get("data") or {}
|
||||
attributes = new_data.pop("attributes")
|
||||
_applications = attributes.pop("applications", None) or []
|
||||
for key, value in attributes.items():
|
||||
if (
|
||||
key in project_doc_data
|
||||
and project_doc_data[key] == value
|
||||
):
|
||||
continue
|
||||
update_dict_data[key] = value
|
||||
|
||||
update_dict_config = {}
|
||||
|
||||
applications = []
|
||||
for application in _applications:
|
||||
if not application:
|
||||
continue
|
||||
if isinstance(application, six.string_types):
|
||||
applications.append({"name": application})
|
||||
|
||||
new_data["apps"] = applications
|
||||
|
||||
for key, value in new_data.items():
|
||||
project_doc_value = project_doc.get(key)
|
||||
if key in project_doc and project_doc_value == value:
|
||||
continue
|
||||
update_dict_config[key] = value
|
||||
|
||||
if not update_dict_data and not update_dict_config:
|
||||
return
|
||||
|
||||
data_changes = self.prepare_mongo_update_dict(update_dict_data)
|
||||
|
||||
# Update dictionary of changes that will be changed in mongo
|
||||
update_dict = {}
|
||||
for key, value in data_changes.items():
|
||||
new_key = "data.{}".format(key)
|
||||
update_dict[new_key] = value
|
||||
|
||||
for key, value in update_dict_config.items():
|
||||
new_key = "config.{}".format(key)
|
||||
update_dict[new_key] = value
|
||||
|
||||
collection.update_one(
|
||||
{"type": "project"},
|
||||
{"$set": update_dict}
|
||||
)
|
||||
|
||||
def _save_project_data(self, project_name, doc_type, data_cache):
|
||||
is_default = bool(project_name is None)
|
||||
replace_filter = {
|
||||
"type": doc_type,
|
||||
"is_default": is_default
|
||||
}
|
||||
replace_data = {
|
||||
"type": doc_type,
|
||||
"data": data_cache.data,
|
||||
"is_default": is_default
|
||||
}
|
||||
if not is_default:
|
||||
replace_filter["project_name"] = project_name
|
||||
replace_data["project_name"] = project_name
|
||||
|
||||
self.collection.replace_one(
|
||||
replace_filter,
|
||||
replace_data,
|
||||
upsert=True
|
||||
)
|
||||
|
||||
def get_studio_system_settings_overrides(self):
|
||||
"""Studio overrides of system settings."""
|
||||
if self.system_settings_cache.is_outdated:
|
||||
document = self.collection.find_one({
|
||||
"type": SYSTEM_SETTINGS_KEY
|
||||
})
|
||||
|
||||
self.system_settings_cache.update_from_document(document)
|
||||
return self.system_settings_cache.data_copy()
|
||||
|
||||
def _get_project_settings_overrides(self, project_name):
|
||||
if self.project_settings_cache[project_name].is_outdated:
|
||||
document_filter = {
|
||||
"type": PROJECT_SETTINGS_KEY,
|
||||
}
|
||||
if project_name is None:
|
||||
document_filter["is_default"] = True
|
||||
else:
|
||||
document_filter["project_name"] = project_name
|
||||
document = self.collection.find_one(document_filter)
|
||||
self.project_settings_cache[project_name].update_from_document(
|
||||
document
|
||||
)
|
||||
return self.project_settings_cache[project_name].data_copy()
|
||||
|
||||
def get_studio_project_settings_overrides(self):
|
||||
"""Studio overrides of default project settings."""
|
||||
return self._get_project_settings_overrides(None)
|
||||
|
||||
def get_project_settings_overrides(self, project_name):
|
||||
"""Studio overrides of project settings for specific project.
|
||||
|
||||
Args:
|
||||
project_name(str): Name of project for which data should be loaded.
|
||||
|
||||
Returns:
|
||||
dict: Only overrides for entered project, may be empty dictionary.
|
||||
"""
|
||||
if not project_name:
|
||||
return {}
|
||||
return self._get_project_settings_overrides(project_name)
|
||||
|
||||
def project_doc_to_anatomy_data(self, project_doc):
|
||||
"""Convert project document to anatomy data.
|
||||
|
||||
Probably should fill missing keys and values.
|
||||
"""
|
||||
if not project_doc:
|
||||
return {}
|
||||
|
||||
attributes = {}
|
||||
project_doc_data = project_doc.get("data") or {}
|
||||
for key in self.attribute_keys:
|
||||
value = project_doc_data.get(key)
|
||||
if value is not None:
|
||||
attributes[key] = value
|
||||
|
||||
project_doc_config = project_doc.get("config") or {}
|
||||
app_names = set()
|
||||
if "apps" in project_doc_config:
|
||||
for app_item in project_doc_config.pop("apps"):
|
||||
if not app_item:
|
||||
continue
|
||||
app_name = app_item.get("name")
|
||||
if app_name:
|
||||
app_names.add(app_name)
|
||||
|
||||
attributes["applications"] = list(app_names)
|
||||
|
||||
output = {"attributes": attributes}
|
||||
for key in self.anatomy_keys:
|
||||
value = project_doc_config.get(key)
|
||||
if value is not None:
|
||||
output[key] = value
|
||||
|
||||
return output
|
||||
|
||||
def _get_project_anatomy_overrides(self, project_name):
|
||||
if self.project_anatomy_cache[project_name].is_outdated:
|
||||
if project_name is None:
|
||||
document_filter = {
|
||||
"type": PROJECT_ANATOMY_KEY,
|
||||
"is_default": True
|
||||
}
|
||||
document = self.collection.find_one(document_filter)
|
||||
self.project_anatomy_cache[project_name].update_from_document(
|
||||
document
|
||||
)
|
||||
else:
|
||||
collection = self.avalon_db.database[project_name]
|
||||
project_doc = collection.find_one({"type": "project"})
|
||||
self.project_anatomy_cache[project_name].update_data(
|
||||
self.project_doc_to_anatomy_data(project_doc)
|
||||
)
|
||||
|
||||
return self.project_anatomy_cache[project_name].data_copy()
|
||||
|
||||
def get_studio_project_anatomy_overrides(self):
|
||||
"""Studio overrides of default project anatomy data."""
|
||||
return self._get_project_anatomy_overrides(None)
|
||||
|
||||
def get_project_anatomy_overrides(self, project_name):
|
||||
"""Studio overrides of project anatomy for specific project.
|
||||
|
||||
Args:
|
||||
project_name(str): Name of project for which data should be loaded.
|
||||
|
||||
Returns:
|
||||
dict: Only overrides for entered project, may be empty dictionary.
|
||||
"""
|
||||
if not project_name:
|
||||
return {}
|
||||
return self._get_project_anatomy_overrides(project_name)
|
||||
|
||||
|
||||
class MongoLocalSettingsHandler(LocalSettingsHandler):
|
||||
"""Settings handler that use mongo for store and load local settings.
|
||||
|
||||
Data have 2 query criteria. First is key "type" stored in constant
|
||||
`LOCAL_SETTING_KEY`. Second is key "site_id" which value can be obstained
|
||||
with `get_local_site_id` function.
|
||||
"""
|
||||
|
||||
def __init__(self, local_site_id=None):
|
||||
# Get mongo connection
|
||||
from openpype.lib import (
|
||||
OpenPypeMongoConnection,
|
||||
get_local_site_id
|
||||
)
|
||||
|
||||
if local_site_id is None:
|
||||
local_site_id = get_local_site_id()
|
||||
settings_collection = OpenPypeMongoConnection.get_mongo_client()
|
||||
|
||||
# TODO prepare version of pype
|
||||
# - pype version should define how are settings saved and loaded
|
||||
|
||||
database_name = os.environ["OPENPYPE_DATABASE_NAME"]
|
||||
# TODO modify to not use hardcoded keys
|
||||
collection_name = "settings"
|
||||
|
||||
self.settings_collection = settings_collection
|
||||
|
||||
self.database_name = database_name
|
||||
self.collection_name = collection_name
|
||||
|
||||
self.collection = settings_collection[database_name][collection_name]
|
||||
|
||||
self.local_site_id = local_site_id
|
||||
|
||||
self.local_settings_cache = CacheValues()
|
||||
|
||||
def save_local_settings(self, data):
|
||||
"""Save local settings.
|
||||
|
||||
Args:
|
||||
data(dict): Data of studio overrides with override metadata.
|
||||
"""
|
||||
data = data or {}
|
||||
|
||||
self.local_settings_cache.update_data(data)
|
||||
|
||||
self.collection.replace_one(
|
||||
{
|
||||
"type": LOCAL_SETTING_KEY,
|
||||
"site_id": self.local_site_id
|
||||
},
|
||||
{
|
||||
"type": LOCAL_SETTING_KEY,
|
||||
"site_id": self.local_site_id,
|
||||
"data": self.local_settings_cache.data
|
||||
},
|
||||
upsert=True
|
||||
)
|
||||
|
||||
def get_local_settings(self):
|
||||
"""Local settings for local site id."""
|
||||
if self.local_settings_cache.is_outdated:
|
||||
document = self.collection.find_one({
|
||||
"type": LOCAL_SETTING_KEY,
|
||||
"site_id": self.local_site_id
|
||||
})
|
||||
|
||||
self.local_settings_cache.update_from_document(document)
|
||||
|
||||
return self.local_settings_cache.data_copy()
|
||||
786
openpype/settings/lib.py
Normal file
786
openpype/settings/lib.py
Normal file
|
|
@ -0,0 +1,786 @@
|
|||
import os
|
||||
import json
|
||||
import functools
|
||||
import logging
|
||||
import platform
|
||||
import copy
|
||||
from .constants import (
|
||||
M_OVERRIDEN_KEY,
|
||||
M_ENVIRONMENT_KEY,
|
||||
|
||||
METADATA_KEYS,
|
||||
|
||||
SYSTEM_SETTINGS_KEY,
|
||||
PROJECT_SETTINGS_KEY,
|
||||
PROJECT_ANATOMY_KEY,
|
||||
DEFAULT_PROJECT_KEY
|
||||
)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# Py2 + Py3 json decode exception
|
||||
JSON_EXC = getattr(json.decoder, "JSONDecodeError", ValueError)
|
||||
|
||||
|
||||
# Path to default settings
|
||||
DEFAULTS_DIR = os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"defaults"
|
||||
)
|
||||
|
||||
# Variable where cache of default settings are stored
|
||||
_DEFAULT_SETTINGS = None
|
||||
|
||||
# Handler of studio overrides
|
||||
_SETTINGS_HANDLER = None
|
||||
|
||||
# Handler of local settings
|
||||
_LOCAL_SETTINGS_HANDLER = None
|
||||
|
||||
|
||||
def require_handler(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
global _SETTINGS_HANDLER
|
||||
if _SETTINGS_HANDLER is None:
|
||||
_SETTINGS_HANDLER = create_settings_handler()
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
|
||||
def require_local_handler(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
global _LOCAL_SETTINGS_HANDLER
|
||||
if _LOCAL_SETTINGS_HANDLER is None:
|
||||
_LOCAL_SETTINGS_HANDLER = create_local_settings_handler()
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
|
||||
def create_settings_handler():
|
||||
from .handlers import MongoSettingsHandler
|
||||
# Handler can't be created in global space on initialization but only when
|
||||
# needed. Plus here may be logic: Which handler is used (in future).
|
||||
return MongoSettingsHandler()
|
||||
|
||||
|
||||
def create_local_settings_handler():
|
||||
from .handlers import MongoLocalSettingsHandler
|
||||
return MongoLocalSettingsHandler()
|
||||
|
||||
|
||||
def calculate_changes(old_value, new_value):
|
||||
changes = {}
|
||||
for key, value in new_value.items():
|
||||
if key not in old_value:
|
||||
changes[key] = value
|
||||
continue
|
||||
|
||||
_value = old_value[key]
|
||||
if isinstance(value, dict) and isinstance(_value, dict):
|
||||
_changes = calculate_changes(_value, value)
|
||||
if _changes:
|
||||
changes[key] = _changes
|
||||
continue
|
||||
|
||||
if _value != value:
|
||||
changes[key] = value
|
||||
return changes
|
||||
|
||||
|
||||
@require_handler
|
||||
def save_studio_settings(data):
|
||||
"""Save studio overrides of system settings.
|
||||
|
||||
Triggers callbacks on modules that want to know about system settings
|
||||
changes.
|
||||
|
||||
Callbacks are triggered on all modules. They must check if their enabled
|
||||
value has changed.
|
||||
|
||||
For saving of data cares registered Settings handler.
|
||||
|
||||
Args:
|
||||
data(dict): Overrides data with metadata defying studio overrides.
|
||||
"""
|
||||
# Notify Pype modules
|
||||
from openpype.modules import ModulesManager, ISettingsChangeListener
|
||||
|
||||
old_data = get_system_settings()
|
||||
default_values = get_default_settings()[SYSTEM_SETTINGS_KEY]
|
||||
new_data = apply_overrides(default_values, copy.deepcopy(data))
|
||||
clear_metadata_from_settings(new_data)
|
||||
|
||||
changes = calculate_changes(old_data, new_data)
|
||||
modules_manager = ModulesManager(_system_settings=new_data)
|
||||
for module in modules_manager.get_enabled_modules():
|
||||
if isinstance(module, ISettingsChangeListener):
|
||||
module.on_system_settings_save(old_data, new_data, changes)
|
||||
|
||||
return _SETTINGS_HANDLER.save_studio_settings(data)
|
||||
|
||||
|
||||
@require_handler
|
||||
def save_project_settings(project_name, overrides):
|
||||
"""Save studio overrides of project settings.
|
||||
|
||||
Old value, new value and changes are passed to enabled modules that want to
|
||||
know about settings changes.
|
||||
|
||||
For saving of data cares registered Settings handler.
|
||||
|
||||
Args:
|
||||
project_name (str): Project name for which overrides are passed.
|
||||
Default project's value is None.
|
||||
overrides(dict): Overrides data with metadata defying studio overrides.
|
||||
"""
|
||||
# Notify Pype modules
|
||||
from openpype.modules import ModulesManager, ISettingsChangeListener
|
||||
|
||||
default_values = get_default_settings()[PROJECT_SETTINGS_KEY]
|
||||
if project_name:
|
||||
old_data = get_project_settings(project_name)
|
||||
|
||||
studio_overrides = get_studio_project_settings_overrides()
|
||||
studio_values = apply_overrides(default_values, studio_overrides)
|
||||
clear_metadata_from_settings(studio_values)
|
||||
new_data = apply_overrides(studio_values, copy.deepcopy(overrides))
|
||||
|
||||
else:
|
||||
old_data = get_default_project_settings(exclude_locals=True)
|
||||
new_data = apply_overrides(default_values, copy.deepcopy(overrides))
|
||||
|
||||
clear_metadata_from_settings(new_data)
|
||||
|
||||
changes = calculate_changes(old_data, new_data)
|
||||
modules_manager = ModulesManager()
|
||||
for module in modules_manager.get_enabled_modules():
|
||||
if isinstance(module, ISettingsChangeListener):
|
||||
module.on_project_settings_save(
|
||||
old_data, new_data, project_name, changes
|
||||
)
|
||||
|
||||
return _SETTINGS_HANDLER.save_project_settings(project_name, overrides)
|
||||
|
||||
|
||||
@require_handler
|
||||
def save_project_anatomy(project_name, anatomy_data):
|
||||
"""Save studio overrides of project anatomy.
|
||||
|
||||
Old value, new value and changes are passed to enabled modules that want to
|
||||
know about settings changes.
|
||||
|
||||
For saving of data cares registered Settings handler.
|
||||
|
||||
Args:
|
||||
project_name (str): Project name for which overrides are passed.
|
||||
Default project's value is None.
|
||||
overrides(dict): Overrides data with metadata defying studio overrides.
|
||||
"""
|
||||
# Notify Pype modules
|
||||
from openpype.modules import ModulesManager, ISettingsChangeListener
|
||||
|
||||
default_values = get_default_settings()[PROJECT_ANATOMY_KEY]
|
||||
if project_name:
|
||||
old_data = get_anatomy_settings(project_name)
|
||||
|
||||
studio_overrides = get_studio_project_settings_overrides()
|
||||
studio_values = apply_overrides(default_values, studio_overrides)
|
||||
clear_metadata_from_settings(studio_values)
|
||||
new_data = apply_overrides(studio_values, copy.deepcopy(anatomy_data))
|
||||
|
||||
else:
|
||||
old_data = get_default_anatomy_settings(exclude_locals=True)
|
||||
new_data = apply_overrides(default_values, copy.deepcopy(anatomy_data))
|
||||
|
||||
clear_metadata_from_settings(new_data)
|
||||
|
||||
changes = calculate_changes(old_data, new_data)
|
||||
modules_manager = ModulesManager()
|
||||
for module in modules_manager.get_enabled_modules():
|
||||
if isinstance(module, ISettingsChangeListener):
|
||||
module.on_project_anatomy_save(
|
||||
old_data, new_data, changes, project_name
|
||||
)
|
||||
|
||||
return _SETTINGS_HANDLER.save_project_anatomy(project_name, anatomy_data)
|
||||
|
||||
|
||||
@require_handler
|
||||
def get_studio_system_settings_overrides():
|
||||
return _SETTINGS_HANDLER.get_studio_system_settings_overrides()
|
||||
|
||||
|
||||
@require_handler
|
||||
def get_studio_project_settings_overrides():
|
||||
return _SETTINGS_HANDLER.get_studio_project_settings_overrides()
|
||||
|
||||
|
||||
@require_handler
|
||||
def get_studio_project_anatomy_overrides():
|
||||
return _SETTINGS_HANDLER.get_studio_project_anatomy_overrides()
|
||||
|
||||
|
||||
@require_handler
|
||||
def get_project_settings_overrides(project_name):
|
||||
return _SETTINGS_HANDLER.get_project_settings_overrides(project_name)
|
||||
|
||||
|
||||
@require_handler
|
||||
def get_project_anatomy_overrides(project_name):
|
||||
return _SETTINGS_HANDLER.get_project_anatomy_overrides(project_name)
|
||||
|
||||
|
||||
@require_local_handler
|
||||
def save_local_settings(data):
|
||||
return _LOCAL_SETTINGS_HANDLER.save_local_settings(data)
|
||||
|
||||
|
||||
@require_local_handler
|
||||
def get_local_settings():
|
||||
return _LOCAL_SETTINGS_HANDLER.get_local_settings()
|
||||
|
||||
|
||||
class DuplicatedEnvGroups(Exception):
|
||||
def __init__(self, duplicated):
|
||||
self.origin_duplicated = duplicated
|
||||
self.duplicated = {}
|
||||
for key, items in duplicated.items():
|
||||
self.duplicated[key] = []
|
||||
for item in items:
|
||||
self.duplicated[key].append("/".join(item["parents"]))
|
||||
|
||||
msg = "Duplicated environment group keys. {}".format(
|
||||
", ".join([
|
||||
"\"{}\"".format(env_key) for env_key in self.duplicated.keys()
|
||||
])
|
||||
)
|
||||
|
||||
super(DuplicatedEnvGroups, self).__init__(msg)
|
||||
|
||||
|
||||
def reset_default_settings():
|
||||
global _DEFAULT_SETTINGS
|
||||
_DEFAULT_SETTINGS = None
|
||||
|
||||
|
||||
def get_default_settings():
|
||||
# TODO add cacher
|
||||
return load_jsons_from_dir(DEFAULTS_DIR)
|
||||
# global _DEFAULT_SETTINGS
|
||||
# if _DEFAULT_SETTINGS is None:
|
||||
# _DEFAULT_SETTINGS = load_jsons_from_dir(DEFAULTS_DIR)
|
||||
# return copy.deepcopy(_DEFAULT_SETTINGS)
|
||||
|
||||
|
||||
def load_json_file(fpath):
|
||||
# Load json data
|
||||
try:
|
||||
with open(fpath, "r") as opened_file:
|
||||
return json.load(opened_file)
|
||||
|
||||
except JSON_EXC:
|
||||
log.warning(
|
||||
"File has invalid json format \"{}\"".format(fpath),
|
||||
exc_info=True
|
||||
)
|
||||
return {}
|
||||
|
||||
|
||||
def load_jsons_from_dir(path, *args, **kwargs):
|
||||
"""Load all .json files with content from entered folder path.
|
||||
|
||||
Data are loaded recursively from a directory and recreate the
|
||||
hierarchy as a dictionary.
|
||||
|
||||
Entered path hiearchy:
|
||||
|_ folder1
|
||||
| |_ data1.json
|
||||
|_ folder2
|
||||
|_ subfolder1
|
||||
|_ data2.json
|
||||
|
||||
Will result in:
|
||||
```javascript
|
||||
{
|
||||
"folder1": {
|
||||
"data1": "CONTENT OF FILE"
|
||||
},
|
||||
"folder2": {
|
||||
"data1": {
|
||||
"subfolder1": "CONTENT OF FILE"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Args:
|
||||
path (str): Path to the root folder where the json hierarchy starts.
|
||||
|
||||
Returns:
|
||||
dict: Loaded data.
|
||||
"""
|
||||
output = {}
|
||||
|
||||
path = os.path.normpath(path)
|
||||
if not os.path.exists(path):
|
||||
# TODO warning
|
||||
return output
|
||||
|
||||
sub_keys = list(kwargs.pop("subkeys", args))
|
||||
for sub_key in tuple(sub_keys):
|
||||
_path = os.path.join(path, sub_key)
|
||||
if not os.path.exists(_path):
|
||||
break
|
||||
|
||||
path = _path
|
||||
sub_keys.pop(0)
|
||||
|
||||
base_len = len(path) + 1
|
||||
for base, _directories, filenames in os.walk(path):
|
||||
base_items_str = base[base_len:]
|
||||
if not base_items_str:
|
||||
base_items = []
|
||||
else:
|
||||
base_items = base_items_str.split(os.path.sep)
|
||||
|
||||
for filename in filenames:
|
||||
basename, ext = os.path.splitext(filename)
|
||||
if ext == ".json":
|
||||
full_path = os.path.join(base, filename)
|
||||
value = load_json_file(full_path)
|
||||
dict_keys = base_items + [basename]
|
||||
output = subkey_merge(output, value, dict_keys)
|
||||
|
||||
for sub_key in sub_keys:
|
||||
output = output[sub_key]
|
||||
return output
|
||||
|
||||
|
||||
def find_environments(data, with_items=False, parents=None):
|
||||
""" Find environemnt values from system settings by it's metadata.
|
||||
|
||||
Args:
|
||||
data(dict): System settings data or dictionary which may contain
|
||||
environments metadata.
|
||||
|
||||
Returns:
|
||||
dict: Key as Environment key and value for `acre` module.
|
||||
"""
|
||||
if not data or not isinstance(data, dict):
|
||||
return {}
|
||||
|
||||
output = {}
|
||||
if parents is None:
|
||||
parents = []
|
||||
|
||||
if M_ENVIRONMENT_KEY in data:
|
||||
metadata = data.get(M_ENVIRONMENT_KEY)
|
||||
for env_group_key, env_keys in metadata.items():
|
||||
if env_group_key not in output:
|
||||
output[env_group_key] = []
|
||||
|
||||
_env_values = {}
|
||||
for key in env_keys:
|
||||
_env_values[key] = data[key]
|
||||
|
||||
item = {
|
||||
"env": _env_values,
|
||||
"parents": parents[:-1]
|
||||
}
|
||||
output[env_group_key].append(item)
|
||||
|
||||
for key, value in data.items():
|
||||
_parents = copy.deepcopy(parents)
|
||||
_parents.append(key)
|
||||
result = find_environments(value, True, _parents)
|
||||
if not result:
|
||||
continue
|
||||
|
||||
for env_group_key, env_values in result.items():
|
||||
if env_group_key not in output:
|
||||
output[env_group_key] = []
|
||||
|
||||
for env_values_item in env_values:
|
||||
output[env_group_key].append(env_values_item)
|
||||
|
||||
if with_items:
|
||||
return output
|
||||
|
||||
duplicated_env_groups = {}
|
||||
final_output = {}
|
||||
for key, value_in_list in output.items():
|
||||
if len(value_in_list) > 1:
|
||||
duplicated_env_groups[key] = value_in_list
|
||||
else:
|
||||
final_output[key] = value_in_list[0]["env"]
|
||||
|
||||
if duplicated_env_groups:
|
||||
raise DuplicatedEnvGroups(duplicated_env_groups)
|
||||
return final_output
|
||||
|
||||
|
||||
def subkey_merge(_dict, value, keys):
|
||||
key = keys.pop(0)
|
||||
if not keys:
|
||||
_dict[key] = value
|
||||
return _dict
|
||||
|
||||
if key not in _dict:
|
||||
_dict[key] = {}
|
||||
_dict[key] = subkey_merge(_dict[key], value, keys)
|
||||
|
||||
return _dict
|
||||
|
||||
|
||||
def merge_overrides(source_dict, override_dict):
|
||||
"""Merge data from override_dict to source_dict."""
|
||||
|
||||
if M_OVERRIDEN_KEY in override_dict:
|
||||
overriden_keys = set(override_dict.pop(M_OVERRIDEN_KEY))
|
||||
else:
|
||||
overriden_keys = set()
|
||||
|
||||
for key, value in override_dict.items():
|
||||
if (key in overriden_keys or key not in source_dict):
|
||||
source_dict[key] = value
|
||||
|
||||
elif isinstance(value, dict) and isinstance(source_dict[key], dict):
|
||||
source_dict[key] = merge_overrides(source_dict[key], value)
|
||||
|
||||
else:
|
||||
source_dict[key] = value
|
||||
return source_dict
|
||||
|
||||
|
||||
def apply_overrides(source_data, override_data):
|
||||
if not override_data:
|
||||
return source_data
|
||||
_source_data = copy.deepcopy(source_data)
|
||||
return merge_overrides(_source_data, override_data)
|
||||
|
||||
|
||||
def apply_local_settings_on_system_settings(system_settings, local_settings):
|
||||
"""Apply local settings on studio system settings.
|
||||
|
||||
ATM local settings can modify only application executables. Executable
|
||||
values are not overriden but prepended.
|
||||
"""
|
||||
if not local_settings or "applications" not in local_settings:
|
||||
return
|
||||
|
||||
current_platform = platform.system().lower()
|
||||
for app_group_name, value in local_settings["applications"].items():
|
||||
if not value or app_group_name not in system_settings["applications"]:
|
||||
continue
|
||||
|
||||
variants = system_settings["applications"][app_group_name]["variants"]
|
||||
for app_name, app_value in value.items():
|
||||
if not app_value or app_name not in variants:
|
||||
continue
|
||||
|
||||
executable = app_value.get("executable")
|
||||
if not executable:
|
||||
continue
|
||||
platform_executables = variants[app_name]["executables"].get(
|
||||
current_platform
|
||||
)
|
||||
# TODO This is temporary fix until launch arguments will be stored
|
||||
# per platform and not per executable.
|
||||
# - local settings store only executable
|
||||
new_executables = [[executable, ""]]
|
||||
new_executables.extend(platform_executables)
|
||||
variants[app_name]["executables"] = new_executables
|
||||
|
||||
|
||||
def apply_local_settings_on_anatomy_settings(
|
||||
anatomy_settings, local_settings, project_name, site_name=None
|
||||
):
|
||||
"""Apply local settings on anatomy settings.
|
||||
|
||||
ATM local settings can modify project roots. Project name is required as
|
||||
local settings have data stored data by project's name.
|
||||
|
||||
Local settings override root values in this order:
|
||||
1.) Check if local settings contain overrides for default project and
|
||||
apply it's values on roots if there are any.
|
||||
2.) If passed `project_name` is not None then check project specific
|
||||
overrides in local settings for the project and apply it's value on
|
||||
roots if there are any.
|
||||
|
||||
NOTE: Root values of default project from local settings are always applied
|
||||
if are set.
|
||||
|
||||
Args:
|
||||
anatomy_settings (dict): Data for anatomy settings.
|
||||
local_settings (dict): Data of local settings.
|
||||
project_name (str): Name of project for which anatomy data are.
|
||||
"""
|
||||
if not local_settings:
|
||||
return
|
||||
|
||||
local_project_settings = local_settings.get("projects") or {}
|
||||
|
||||
# Check for roots existence in local settings first
|
||||
roots_project_locals = (
|
||||
local_project_settings
|
||||
.get(project_name, {})
|
||||
)
|
||||
roots_default_locals = (
|
||||
local_project_settings
|
||||
.get(DEFAULT_PROJECT_KEY, {})
|
||||
)
|
||||
|
||||
# Skip rest of processing if roots are not set
|
||||
if not roots_project_locals and not roots_default_locals:
|
||||
return
|
||||
|
||||
# Get active site from settings
|
||||
if site_name is None:
|
||||
if project_name:
|
||||
project_settings = get_project_settings(project_name)
|
||||
else:
|
||||
project_settings = get_default_project_settings()
|
||||
site_name = (
|
||||
project_settings["global"]["sync_server"]["config"]["active_site"]
|
||||
)
|
||||
|
||||
# QUESTION should raise an exception?
|
||||
if not site_name:
|
||||
return
|
||||
|
||||
# Combine roots from local settings
|
||||
roots_locals = roots_default_locals.get(site_name) or {}
|
||||
roots_locals.update(roots_project_locals.get(site_name) or {})
|
||||
# Skip processing if roots for current active site are not available in
|
||||
# local settings
|
||||
if not roots_locals:
|
||||
return
|
||||
|
||||
current_platform = platform.system().lower()
|
||||
|
||||
root_data = anatomy_settings["roots"]
|
||||
for root_name, path in roots_locals.items():
|
||||
if root_name not in root_data:
|
||||
continue
|
||||
anatomy_settings["roots"][root_name][current_platform] = (
|
||||
path
|
||||
)
|
||||
|
||||
|
||||
def get_site_local_overrides(project_name, site_name, local_settings=None):
|
||||
"""Site overrides from local settings for passet project and site name.
|
||||
|
||||
Args:
|
||||
project_name (str): For which project are overrides.
|
||||
site_name (str): For which site are overrides needed.
|
||||
local_settings (dict): Preloaded local settings. They are loaded
|
||||
automatically if not passed.
|
||||
"""
|
||||
# Check if local settings were passed
|
||||
if local_settings is None:
|
||||
local_settings = get_local_settings()
|
||||
|
||||
output = {}
|
||||
|
||||
# Skip if local settings are empty
|
||||
if not local_settings:
|
||||
return output
|
||||
|
||||
local_project_settings = local_settings.get("projects") or {}
|
||||
|
||||
# Prepare overrides for entered project and for default project
|
||||
project_locals = None
|
||||
if project_name:
|
||||
project_locals = local_project_settings.get(project_name)
|
||||
default_project_locals = local_project_settings.get(DEFAULT_PROJECT_KEY)
|
||||
|
||||
# First load and use local settings from default project
|
||||
if default_project_locals and site_name in default_project_locals:
|
||||
output.update(default_project_locals[site_name])
|
||||
|
||||
# Apply project specific local settings if there are any
|
||||
if project_locals and site_name in project_locals:
|
||||
output.update(project_locals[site_name])
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def apply_local_settings_on_project_settings(
|
||||
project_settings, local_settings, project_name
|
||||
):
|
||||
"""Apply local settings on project settings.
|
||||
|
||||
Currently is modifying active site and remote site in sync server.
|
||||
|
||||
Args:
|
||||
project_settings (dict): Data for project settings.
|
||||
local_settings (dict): Data of local settings.
|
||||
project_name (str): Name of project for which settings data are.
|
||||
"""
|
||||
if not local_settings:
|
||||
return
|
||||
|
||||
local_project_settings = local_settings.get("projects")
|
||||
if not local_project_settings:
|
||||
return
|
||||
|
||||
project_locals = local_project_settings.get(project_name) or {}
|
||||
default_locals = local_project_settings.get(DEFAULT_PROJECT_KEY) or {}
|
||||
active_site = (
|
||||
project_locals.get("active_site")
|
||||
or default_locals.get("active_site")
|
||||
)
|
||||
remote_site = (
|
||||
project_locals.get("remote_site")
|
||||
or default_locals.get("remote_site")
|
||||
)
|
||||
|
||||
sync_server_config = project_settings["global"]["sync_server"]["config"]
|
||||
if active_site:
|
||||
sync_server_config["active_site"] = active_site
|
||||
|
||||
if remote_site:
|
||||
sync_server_config["remote_site"] = remote_site
|
||||
|
||||
|
||||
def get_system_settings(clear_metadata=True):
|
||||
"""System settings with applied studio overrides."""
|
||||
default_values = get_default_settings()[SYSTEM_SETTINGS_KEY]
|
||||
studio_values = get_studio_system_settings_overrides()
|
||||
result = apply_overrides(default_values, studio_values)
|
||||
if clear_metadata:
|
||||
clear_metadata_from_settings(result)
|
||||
# TODO local settings may be required to apply for environments
|
||||
local_settings = get_local_settings()
|
||||
apply_local_settings_on_system_settings(result, local_settings)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_default_project_settings(clear_metadata=True, exclude_locals=False):
|
||||
"""Project settings with applied studio's default project overrides."""
|
||||
default_values = get_default_settings()[PROJECT_SETTINGS_KEY]
|
||||
studio_values = get_studio_project_settings_overrides()
|
||||
result = apply_overrides(default_values, studio_values)
|
||||
if clear_metadata:
|
||||
clear_metadata_from_settings(result)
|
||||
if not exclude_locals:
|
||||
local_settings = get_local_settings()
|
||||
apply_local_settings_on_project_settings(
|
||||
result, local_settings, None
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
def get_default_anatomy_settings(clear_metadata=True, exclude_locals=False):
|
||||
"""Project anatomy data with applied studio's default project overrides."""
|
||||
default_values = get_default_settings()[PROJECT_ANATOMY_KEY]
|
||||
studio_values = get_studio_project_anatomy_overrides()
|
||||
|
||||
# TODO uncomment and remove hotfix result when overrides of anatomy
|
||||
# are stored correctly.
|
||||
result = apply_overrides(default_values, studio_values)
|
||||
if clear_metadata:
|
||||
clear_metadata_from_settings(result)
|
||||
if not exclude_locals:
|
||||
local_settings = get_local_settings()
|
||||
apply_local_settings_on_anatomy_settings(
|
||||
result, local_settings, None
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
def get_anatomy_settings(project_name, site_name=None, exclude_locals=False):
|
||||
"""Project anatomy data with applied studio and project overrides."""
|
||||
if not project_name:
|
||||
raise ValueError(
|
||||
"Must enter project name. Call "
|
||||
"`get_default_anatomy_settings` to get project defaults."
|
||||
)
|
||||
|
||||
studio_overrides = get_default_anatomy_settings(False)
|
||||
project_overrides = get_project_anatomy_overrides(
|
||||
project_name
|
||||
)
|
||||
result = copy.deepcopy(studio_overrides)
|
||||
if project_overrides:
|
||||
for key, value in project_overrides.items():
|
||||
result[key] = value
|
||||
|
||||
clear_metadata_from_settings(result)
|
||||
|
||||
if not exclude_locals:
|
||||
local_settings = get_local_settings()
|
||||
apply_local_settings_on_anatomy_settings(
|
||||
result, local_settings, project_name, site_name
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
def get_project_settings(project_name, exclude_locals=False):
|
||||
"""Project settings with applied studio and project overrides."""
|
||||
if not project_name:
|
||||
raise ValueError(
|
||||
"Must enter project name."
|
||||
" Call `get_default_project_settings` to get project defaults."
|
||||
)
|
||||
|
||||
studio_overrides = get_default_project_settings(False)
|
||||
project_overrides = get_project_settings_overrides(
|
||||
project_name
|
||||
)
|
||||
|
||||
result = apply_overrides(studio_overrides, project_overrides)
|
||||
clear_metadata_from_settings(result)
|
||||
|
||||
if not exclude_locals:
|
||||
local_settings = get_local_settings()
|
||||
apply_local_settings_on_project_settings(
|
||||
result, local_settings, project_name
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_current_project_settings():
|
||||
"""Project settings for current context project.
|
||||
|
||||
Project name should be stored in environment variable `AVALON_PROJECT`.
|
||||
This function should be used only in host context where environment
|
||||
variable must be set and should not happen that any part of process will
|
||||
change the value of the enviornment variable.
|
||||
"""
|
||||
project_name = os.environ.get("AVALON_PROJECT")
|
||||
if not project_name:
|
||||
raise ValueError(
|
||||
"Missing context project in environemt variable `AVALON_PROJECT`."
|
||||
)
|
||||
return get_project_settings(project_name)
|
||||
|
||||
|
||||
def get_environments():
|
||||
"""Calculated environment based on defaults and system settings.
|
||||
|
||||
Any default environment also found in the system settings will be fully
|
||||
overriden by the one from the system settings.
|
||||
|
||||
Returns:
|
||||
dict: Output should be ready for `acre` module.
|
||||
"""
|
||||
|
||||
return find_environments(get_system_settings(False))
|
||||
|
||||
|
||||
def clear_metadata_from_settings(values):
|
||||
"""Remove all metadata keys from loaded settings."""
|
||||
if isinstance(values, dict):
|
||||
for key in tuple(values.keys()):
|
||||
if key in METADATA_KEYS:
|
||||
values.pop(key)
|
||||
else:
|
||||
clear_metadata_from_settings(values[key])
|
||||
elif isinstance(values, list):
|
||||
for item in values:
|
||||
clear_metadata_from_settings(item)
|
||||
79
openpype/settings/local_settings.md
Normal file
79
openpype/settings/local_settings.md
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# Structure of local settings
|
||||
- local settings do not have any validation schemas right now this should help to see what is stored to local settings and how it works
|
||||
- they are stored by identifier site_id which should be unified identifier of workstation
|
||||
- all keys may and may not available on load
|
||||
- contain main categories: `general`, `applications`, `projects`
|
||||
|
||||
## Categories
|
||||
### General
|
||||
- ATM contain only label of site
|
||||
```json
|
||||
{
|
||||
"general": {
|
||||
"site_label": "MySite"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Applications
|
||||
- modifications of application executables
|
||||
- output should match application groups and variants
|
||||
```json
|
||||
{
|
||||
"applications": {
|
||||
"<app group>": {
|
||||
"<app name>": {
|
||||
"executable": "/my/path/to/nuke_12_2"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Projects
|
||||
- project specific modifications
|
||||
- default project is stored under constant key defined in `pype.settings.contants`
|
||||
```json
|
||||
{
|
||||
"projects": {
|
||||
"<project name>": {
|
||||
"active_site": "<name of active site>",
|
||||
"remote_site": "<name of remote site>",
|
||||
"roots": {
|
||||
"<site name>": {
|
||||
"<root name>": "<root dir path>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Final document
|
||||
```json
|
||||
{
|
||||
"_id": "<ObjectId(...)>",
|
||||
"site_id": "<site id>",
|
||||
"general": {
|
||||
"site_label": "MySite"
|
||||
},
|
||||
"applications": {
|
||||
"<app group>": {
|
||||
"<app name>": {
|
||||
"executable": "<path to app executable>"
|
||||
}
|
||||
}
|
||||
},
|
||||
"projects": {
|
||||
"<project name>": {
|
||||
"active_site": "<name of active site>",
|
||||
"remote_site": "<name of remote site>",
|
||||
"roots": {
|
||||
"<site name>": {
|
||||
"<root name>": "<root dir path>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue