.*)_(.*)_SHD"
+ },
+ "ValidateAttributes": {
+ "enabled": false,
+ "attributes": {}
},
"ValidateModelName": {
- "enabled": true,
+ "enabled": false,
"material_file": {
"windows": "",
"darwin": "",
"linux": ""
},
- "regex": ""
+ "regex": "(.*)_(\\\\d)*_(.*)_(GEO)"
},
- "ValidateAssemblyName": {
- "enabled": true
- },
- "ValidateShaderName": {
+ "ValidateTransformNamingSuffix": {
"enabled": true,
- "regex": ""
+ "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
},
"ValidateMeshHasOverlappingUVs": {
- "enabled": false
- },
- "ValidateAttributes": {
"enabled": false,
- "attributes": {}
+ "optional": true
+ },
+ "ValidateMeshArnoldAttributes": {
+ "enabled": false,
+ "optional": true
+ },
+ "ValidateMeshShaderConnections": {
+ "enabled": true,
+ "optional": true
+ },
+ "ValidateMeshSingleUVSet": {
+ "enabled": false,
+ "optional": true
+ },
+ "ValidateMeshHasUVs": {
+ "enabled": true,
+ "optional": true
+ },
+ "ValidateMeshLaminaFaces": {
+ "enabled": false,
+ "optional": true
+ },
+ "ValidateMeshNonManifold": {
+ "enabled": false,
+ "optional": true
+ },
+ "ValidateMeshUVSetMap1": {
+ "enabled": false,
+ "optional": true
+ },
+ "ValidateMeshVerticesHaveEdges": {
+ "enabled": true,
+ "optional": true
+ },
+ "ValidateNoAnimation": {
+ "enabled": false,
+ "optional": true
+ },
+ "ValidateNoNamespace": {
+ "enabled": true,
+ "optional": true
+ },
+ "ValidateNoNullTransforms": {
+ "enabled": true,
+ "optional": true
+ },
+ "ValidateNoUnknownNodes": {
+ "enabled": true,
+ "optional": true
+ },
+ "ValidateNodeNoGhosting": {
+ "enabled": false,
+ "optional": true
+ },
+ "ValidateShapeDefaultNames": {
+ "enabled": false,
+ "optional": true
+ },
+ "ValidateShapeRenderStats": {
+ "enabled": false,
+ "optional": true
+ },
+ "ValidateTransformZero": {
+ "enabled": true,
+ "optional": true
+ },
+ "ValidateCameraAttributes": {
+ "enabled": false,
+ "optional": true
+ },
+ "ValidateAssemblyName": {
+ "enabled": true,
+ "optional": true
+ },
+ "ValidateAssRelativePaths": {
+ "enabled": true,
+ "optional": true
},
"ExtractCameraAlembic": {
"enabled": true,
@@ -221,6 +433,39 @@
0.8,
0.5
]
+ },
+ "ReferenceLoader": {
+ "enabled": true,
+ "representations": [
+ "ma",
+ "mb",
+ "abc",
+ "fbx"
+ ]
+ },
+ "AudioLoader": {
+ "enabled": true,
+ "representations": [
+ "wav"
+ ]
+ },
+ "GpuCacheLoader": {
+ "enabled": true,
+ "representations": [
+ "abc"
+ ]
+ },
+ "ImagePlaneLoader": {
+ "enabled": true,
+ "representations": [
+ "jpg",
+ "png",
+ "mov"
+ ]
+ },
+ "MatchmoveLoader": {
+ "enabled": true,
+ "representations": []
}
},
"workfile_build": {
diff --git a/pype/settings/defaults/project_settings/nuke.json b/pype/settings/defaults/project_settings/nuke.json
index 94cd712639..517065f79a 100644
--- a/pype/settings/defaults/project_settings/nuke.json
+++ b/pype/settings/defaults/project_settings/nuke.json
@@ -61,6 +61,22 @@
"deadline_pool": "",
"deadline_pool_secondary": "",
"deadline_chunk_size": 1
+ },
+ "ValidateOutputResolution": {
+ "enabled": true,
+ "optional": true
+ },
+ "ValidateGizmo": {
+ "enabled": true,
+ "optional": true
+ },
+ "ValidateScript": {
+ "enabled": true,
+ "optional": true
+ },
+ "ValidateNukeWriteBoundingBox": {
+ "enabled": true,
+ "optional": true
}
},
"workfile_build": {
diff --git a/pype/settings/entities/base_entity.py b/pype/settings/entities/base_entity.py
index b2be6819d5..9003a66d76 100644
--- a/pype/settings/entities/base_entity.py
+++ b/pype/settings/entities/base_entity.py
@@ -695,6 +695,12 @@ class ItemEntity(BaseItemEntity):
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)
@@ -736,12 +742,50 @@ class ItemEntity(BaseItemEntity):
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:
+ raise ValueError((
+ "{} Entity has set `use_label_wrap` to true but"
+ " does not have set `label`."
+ ).format(self.path))
+
+ 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)
diff --git a/pype/settings/entities/dict_immutable_keys_entity.py b/pype/settings/entities/dict_immutable_keys_entity.py
index 854c904f3c..af0ddcb758 100644
--- a/pype/settings/entities/dict_immutable_keys_entity.py
+++ b/pype/settings/entities/dict_immutable_keys_entity.py
@@ -27,6 +27,11 @@ class DictImmutableKeysEntity(ItemEntity):
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."""
@@ -130,7 +135,7 @@ class DictImmutableKeysEntity(ItemEntity):
continue
if child_obj.key in self.non_gui_children:
- raise SchemaDuplicatedKeys(self.path, child_obj.key)
+ raise SchemaDuplicatedKeys("", child_obj.key)
self.non_gui_children[child_obj.key] = child_obj
if not first:
@@ -169,11 +174,6 @@ class DictImmutableKeysEntity(ItemEntity):
"highlight_content", False
)
self.show_borders = self.schema_data.get("show_borders", True)
- self.collapsible = self.schema_data.get("collapsible", True)
- self.collapsed = self.schema_data.get("collapsed", True)
-
- # Not yet implemented
- self.use_label_wrap = self.schema_data.get("use_label_wrap") or True
def get_child_path(self, child_obj):
"""Get hierarchical path of child entity.
diff --git a/pype/settings/entities/dict_mutable_keys_entity.py b/pype/settings/entities/dict_mutable_keys_entity.py
index 8fe71db2a3..2fd2b87311 100644
--- a/pype/settings/entities/dict_mutable_keys_entity.py
+++ b/pype/settings/entities/dict_mutable_keys_entity.py
@@ -29,6 +29,12 @@ class DictMutableKeysEntity(EndpointEntity):
- clear callbacks
"""
schema_types = ["dict-modifiable"]
+ _default_label_wrap = {
+ "use_label_wrap": True,
+ "collapsible": True,
+ "collapsed": True
+ }
+
_miss_arg = object()
def __getitem__(self, key):
@@ -174,8 +180,6 @@ class DictMutableKeysEntity(EndpointEntity):
self.hightlight_content = (
self.schema_data.get("highlight_content") or False
)
- self.collapsible = self.schema_data.get("collapsible", True)
- self.collapsed = self.schema_data.get("collapsed", True)
object_type = self.schema_data["object_type"]
if not isinstance(object_type, dict):
diff --git a/pype/settings/entities/list_entity.py b/pype/settings/entities/list_entity.py
index 07221929b7..752347489a 100644
--- a/pype/settings/entities/list_entity.py
+++ b/pype/settings/entities/list_entity.py
@@ -15,6 +15,11 @@ from .exceptions import (
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:
@@ -139,12 +144,6 @@ class ListEntity(EndpointEntity):
# Value that was set on set_override_state
self.initial_value = []
- # GUI attributes
- self.use_label_wrap = self.schema_data.get("use_label_wrap") or False
- # Used only if `use_label_wrap` is set to True
- self.collapsible = self.schema_data.get("collapsible") or True
- self.collapsed = self.schema_data.get("collapsed") or False
-
def schema_validations(self):
super(ListEntity, self).schema_validations()
diff --git a/pype/settings/entities/schemas/projects_schema/schema_main.json b/pype/settings/entities/schemas/projects_schema/schema_main.json
index 8ad059f1c7..31d7373873 100644
--- a/pype/settings/entities/schemas/projects_schema/schema_main.json
+++ b/pype/settings/entities/schemas/projects_schema/schema_main.json
@@ -45,6 +45,10 @@
"type": "schema",
"name": "schema_project_ftrack"
},
+ {
+ "type": "schema",
+ "name": "schema_project_deadline"
+ },
{
"type": "schema",
"name": "schema_project_maya"
diff --git a/pype/settings/entities/schemas/projects_schema/schema_plugins.json b/pype/settings/entities/schemas/projects_schema/schema_plugins.json
deleted file mode 100644
index a7ed64be17..0000000000
--- a/pype/settings/entities/schemas/projects_schema/schema_plugins.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
- "type": "dict",
- "collapsible": true,
- "key": "plugins",
- "label": "Plugins",
- "children": [
- {
- "type": "dict",
- "collapsible": true,
- "key": "standalonepublisher",
- "label": "Standalone Publisher",
- "children": [
- {
- "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"
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- }
- ]
-}
diff --git a/pype/settings/entities/schemas/projects_schema/schema_project_deadline.json b/pype/settings/entities/schemas/projects_schema/schema_project_deadline.json
new file mode 100644
index 0000000000..ea76f4e62e
--- /dev/null
+++ b/pype/settings/entities/schemas/projects_schema/schema_project_deadline.json
@@ -0,0 +1,223 @@
+{
+ "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": "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": "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": "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": "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": "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": "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"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/pype/settings/entities/schemas/projects_schema/schema_project_global.json b/pype/settings/entities/schemas/projects_schema/schema_project_global.json
index fa5db9af88..1733e04f67 100644
--- a/pype/settings/entities/schemas/projects_schema/schema_project_global.json
+++ b/pype/settings/entities/schemas/projects_schema/schema_project_global.json
@@ -16,7 +16,8 @@
{
"type": "raw-json",
"label": "Project Folder Structure",
- "key": "project_folder_structure"
+ "key": "project_folder_structure",
+ "use_label_wrap": true
},
{
"type": "schema",
diff --git a/pype/settings/entities/schemas/projects_schema/schema_project_harmony.json b/pype/settings/entities/schemas/projects_schema/schema_project_harmony.json
index 5d1cbff1b8..c4cdccff42 100644
--- a/pype/settings/entities/schemas/projects_schema/schema_project_harmony.json
+++ b/pype/settings/entities/schemas/projects_schema/schema_project_harmony.json
@@ -5,13 +5,6 @@
"label": "Harmony",
"is_file": true,
"children": [
- {
- "type": "dict",
- "collapsible": true,
- "key": "publish",
- "label": "Publish plugins",
- "children": []
- },
{
"type": "dict",
"collapsible": true,
@@ -31,6 +24,61 @@
"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"
+ }
+ ]
+ }
+ ]
}
]
}
diff --git a/pype/settings/entities/schemas/projects_schema/schema_project_maya.json b/pype/settings/entities/schemas/projects_schema/schema_project_maya.json
index 5ba5de1557..7a270b0046 100644
--- a/pype/settings/entities/schemas/projects_schema/schema_project_maya.json
+++ b/pype/settings/entities/schemas/projects_schema/schema_project_maya.json
@@ -9,6 +9,10 @@
"type": "schema",
"name": "schema_maya_capture"
},
+ {
+ "type": "schema",
+ "name": "schema_maya_create"
+ },
{
"type": "schema",
"name": "schema_maya_publish"
diff --git a/pype/settings/entities/schemas/projects_schema/schema_project_nuke.json b/pype/settings/entities/schemas/projects_schema/schema_project_nuke.json
index b60b548cb0..0548bd3544 100644
--- a/pype/settings/entities/schemas/projects_schema/schema_project_nuke.json
+++ b/pype/settings/entities/schemas/projects_schema/schema_project_nuke.json
@@ -9,7 +9,7 @@
"type": "dict",
"collapsible": true,
"key": "create",
- "label": "Create plugins",
+ "label": "Creator plugins",
"children": [
{
"type": "dict",
@@ -42,144 +42,9 @@
]
},
{
- "type": "dict",
- "collapsible": true,
- "key": "publish",
- "label": "Publish plugins",
- "children": [
- {
- "type": "dict",
- "collapsible": true,
- "key": "PreCollectNukeInstances",
- "label": "PreCollectNukeInstances",
- "is_group": true,
- "children": [
- {
- "type": "boolean",
- "key": "sync_workfile_version",
- "label": "Sync Version from workfile"
- }
- ]
- },
- {
- "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": "ValidateKnobs",
- "label": "ValidateKnobs",
- "is_group": true,
- "children": [
- {
- "type": "boolean",
- "key": "enabled",
- "label": "Enabled"
- },
- {
- "type": "raw-json",
- "key": "knobs",
- "label": "Knobs"
- }
- ]
- },
- {
- "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"
- }
- ]
- }
- ]
+ "type": "schema",
+ "name": "schema_nuke_publish",
+ "template_data": []
},
{
"type": "schema",
diff --git a/pype/settings/entities/schemas/projects_schema/schema_project_standalonepublisher.json b/pype/settings/entities/schemas/projects_schema/schema_project_standalonepublisher.json
index 735b9611d2..47eea3441c 100644
--- a/pype/settings/entities/schemas/projects_schema/schema_project_standalonepublisher.json
+++ b/pype/settings/entities/schemas/projects_schema/schema_project_standalonepublisher.json
@@ -5,44 +5,6 @@
"label": "Standalone Publisher",
"is_file": true,
"children": [
- {
- "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"
- }
- ]
- }
- ]
- }
- ]
- },
{
"type": "dict-modifiable",
"collapsible": true,
@@ -88,6 +50,44 @@
}
]
}
+ },
+ {
+ "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"
+ }
+ ]
+ }
+ ]
+ }
+ ]
}
]
}
diff --git a/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json b/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json
index 648fca28e6..4745a19075 100644
--- a/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json
+++ b/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json
@@ -1,595 +1,581 @@
{
- "type": "collapsible-wrap",
- "label": "Collapsible Wrapper without key",
+ "type": "dict",
+ "collapsible": true,
+ "key": "capture",
+ "label": "Maya Playblast settings",
+ "is_file": true,
"children": [
{
"type": "dict",
- "collapsible": true,
- "key": "capture",
- "label": "Maya Playblast settings",
- "is_file": true,
+ "key": "Codec",
"children": [
{
- "type": "dict",
- "key": "Codec",
- "children": [
- {
- "type": "label",
- "label": "Codec"
- },
- {
- "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": "label",
+ "label": "Codec"
+ },
+ {
+ "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": "Display Options"
- },
- {
- "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": "Generic"
- },
- {
- "type": "boolean",
- "key": "isolate_view",
- "label": " Isolate view"
- },
- {
- "type": "boolean",
- "key": "off_screen",
- "label": " Off Screen"
- }
- ]
- },
- {
- "type": "dict",
- "key": "IO",
- "children": [
- {
- "type": "label",
- "label": "IO"
- },
- {
- "type": "text",
- "key": "name",
- "label": "Name"
- },
- {
- "type": "boolean",
- "key": "open_finished",
- "label": "Open finished"
- },
- {
- "type": "boolean",
- "key": "raw_frame_numbers",
- "label": "Raw frame numbers"
- },
- {
- "type": "list",
- "key": "recent_playblasts",
- "label": "Recent Playblasts",
- "object_type": "text"
- },
- {
- "type": "boolean",
- "key": "save_file",
- "label": "Save file"
- }
- ]
- },
- {
- "type": "dict",
- "key": "PanZoom",
- "children": [
- {
- "type": "boolean",
- "key": "pan_zoom",
- "label": " Pan Zoom"
- }
- ]
- },
- {
- "type": "splitter"
- },
- {
- "type": "dict",
- "key": "Renderer",
- "children": [
- {
- "type": "label",
- "label": "Renderer"
- },
- {
- "type": "text",
- "key": "rendererName",
- "label": " Renderer name"
- }
- ]
- },
- {
- "type": "dict",
- "key": "Resolution",
- "children": [
- {
- "type": "splitter"
- },
- {
- "type": "label",
- "label": "Resolution"
- },
- {
- "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",
- "key": "Time Range",
- "children": [
- {
- "type": "label",
- "label": "Time Range"
- },
- {
- "type": "number",
- "key": "start_frame",
- "label": " Start frame",
- "decimal": 0,
- "minimum": 0,
- "maximum": 999999
- },
- {
- "type": "number",
- "key": "end_frame",
- "label": "End frame",
- "decimal": 0,
- "minimum": 0,
- "maximum": 999999
- },
- {
- "type": "text",
- "key": "frame",
- "label": "Frame"
- },
- {
- "type": "text",
- "key": "time",
- "label": "Time"
- }
- ]
- },
- {
- "type": "dict",
- "collapsible": true,
- "key": "Viewport Options",
- "label": "Viewport Options",
- "children": [
- {
- "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": "number",
- "key": "displayLights",
- "label": "displayLights",
- "decimal": 0,
- "minimum": 0,
- "maximum": 10
- },
- {
- "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": "high_quality",
- "label": "high_quality"
- },
- {
- "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": "override_viewport_options",
- "label": "override_viewport_options"
- },
- {
- "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": "shadows",
- "label": "shadows"
- },
- {
- "type": "boolean",
- "key": "strokes",
- "label": "strokes"
- },
- {
- "type": "boolean",
- "key": "subdivSurfaces",
- "label": "subdivSurfaces"
- },
- {
- "type": "boolean",
- "key": "textures",
- "label": "textures"
- },
- {
- "type": "boolean",
- "key": "twoSidedLighting",
- "label": "twoSidedLighting"
- }
- ]
- },
- {
- "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
- }
- ]
}
]
},
{
- "type": "dict-modifiable",
- "key": "ext_mapping",
- "label": "Extension Mapping",
- "object_type": {
- "type": "text"
- }
+ "type": "dict",
+ "key": "Display Options",
+ "children": [
+ {
+ "type": "label",
+ "label": "Display Options"
+ },
+ {
+ "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": "Generic"
+ },
+ {
+ "type": "boolean",
+ "key": "isolate_view",
+ "label": " Isolate view"
+ },
+ {
+ "type": "boolean",
+ "key": "off_screen",
+ "label": " Off Screen"
+ }
+ ]
+ },
+ {
+ "type": "dict",
+ "key": "IO",
+ "children": [
+ {
+ "type": "label",
+ "label": "IO"
+ },
+ {
+ "type": "text",
+ "key": "name",
+ "label": "Name"
+ },
+ {
+ "type": "boolean",
+ "key": "open_finished",
+ "label": "Open finished"
+ },
+ {
+ "type": "boolean",
+ "key": "raw_frame_numbers",
+ "label": "Raw frame numbers"
+ },
+ {
+ "type": "list",
+ "key": "recent_playblasts",
+ "label": "Recent Playblasts",
+ "object_type": "text"
+ },
+ {
+ "type": "boolean",
+ "key": "save_file",
+ "label": "Save file"
+ }
+ ]
+ },
+ {
+ "type": "dict",
+ "key": "PanZoom",
+ "children": [
+ {
+ "type": "boolean",
+ "key": "pan_zoom",
+ "label": " Pan Zoom"
+ }
+ ]
+ },
+ {
+ "type": "splitter"
+ },
+ {
+ "type": "dict",
+ "key": "Renderer",
+ "children": [
+ {
+ "type": "label",
+ "label": "Renderer"
+ },
+ {
+ "type": "text",
+ "key": "rendererName",
+ "label": " Renderer name"
+ }
+ ]
+ },
+ {
+ "type": "dict",
+ "key": "Resolution",
+ "children": [
+ {
+ "type": "splitter"
+ },
+ {
+ "type": "label",
+ "label": "Resolution"
+ },
+ {
+ "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",
+ "key": "Time Range",
+ "children": [
+ {
+ "type": "label",
+ "label": "Time Range"
+ },
+ {
+ "type": "number",
+ "key": "start_frame",
+ "label": " Start frame",
+ "decimal": 0,
+ "minimum": 0,
+ "maximum": 999999
+ },
+ {
+ "type": "number",
+ "key": "end_frame",
+ "label": "End frame",
+ "decimal": 0,
+ "minimum": 0,
+ "maximum": 999999
+ },
+ {
+ "type": "text",
+ "key": "frame",
+ "label": "Frame"
+ },
+ {
+ "type": "text",
+ "key": "time",
+ "label": "Time"
+ }
+ ]
+ },
+ {
+ "type": "dict",
+ "collapsible": true,
+ "key": "Viewport Options",
+ "label": "Viewport Options",
+ "children": [
+ {
+ "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": "number",
+ "key": "displayLights",
+ "label": "displayLights",
+ "decimal": 0,
+ "minimum": 0,
+ "maximum": 10
+ },
+ {
+ "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": "high_quality",
+ "label": "high_quality"
+ },
+ {
+ "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": "override_viewport_options",
+ "label": "override_viewport_options"
+ },
+ {
+ "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": "shadows",
+ "label": "shadows"
+ },
+ {
+ "type": "boolean",
+ "key": "strokes",
+ "label": "strokes"
+ },
+ {
+ "type": "boolean",
+ "key": "subdivSurfaces",
+ "label": "subdivSurfaces"
+ },
+ {
+ "type": "boolean",
+ "key": "textures",
+ "label": "textures"
+ },
+ {
+ "type": "boolean",
+ "key": "twoSidedLighting",
+ "label": "twoSidedLighting"
+ }
+ ]
+ },
+ {
+ "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
+ }
+ ]
}
]
}
diff --git a/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_create.json b/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_create.json
new file mode 100644
index 0000000000..575e04c85d
--- /dev/null
+++ b/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_create.json
@@ -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"
+ }
+ ]
+ }
+ ]
+}
diff --git a/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_load.json b/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_load.json
index dd9d0508b4..3615c1477c 100644
--- a/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_load.json
+++ b/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_load.json
@@ -151,6 +151,32 @@
]
}
]
+ },
+ {
+ "type": "schema_template",
+ "name": "template_loader_plugin",
+ "template_data": [
+ {
+ "key": "ReferenceLoader",
+ "label": "Reference Loader"
+ },
+ {
+ "key": "AudioLoader",
+ "label": "Audio Loader"
+ },
+ {
+ "key": "GpuCacheLoader",
+ "label": "GpuCache Loader"
+ },
+ {
+ "key": "ImagePlaneLoader",
+ "label": "Imageplane Loader"
+ },
+ {
+ "key": "MatchmoveLoader",
+ "label": "Matchmove Loader"
+ }
+ ]
}
]
}
diff --git a/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json b/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json
index 0d705d3d02..58a21c185a 100644
--- a/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json
+++ b/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json
@@ -26,71 +26,9 @@
},
{
"type": "label",
- "label": "Collectors"
- },
- {
- "type": "dict",
- "collapsible": true,
- "key": "ValidateCameraAttributes",
- "label": "Validate Camera Attributes",
- "checkbox_key": "enabled",
- "children": [
- {
- "type": "boolean",
- "key": "enabled",
- "label": "Enabled"
- },
- {
- "type": "boolean",
- "key": "optional",
- "label": "Optional"
- }
- ]
- },
- {
- "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.
It will be checked against named group shader in your Validation regex.For example:
^.*(?P=<shader>.+)_GEO
"
- },
- {
- "type": "path-widget",
- "key": "material_file",
- "label": "Material File",
- "multiplatform": true,
- "multipath": false
- },
- {
- "type": "text",
- "key": "regex",
- "label": "Validation regex"
- }
- ]
- },
- {
- "type": "dict",
- "collapsible": true,
- "key": "ValidateAssemblyName",
- "label": "Validate Assembly Name",
- "checkbox_key": "enabled",
- "children": [
- {
- "type": "boolean",
- "key": "enabled",
- "label": "Enabled"
- }
- ]
+ "label": "Validators"
},
+
{
"type": "dict",
"collapsible": true,
@@ -114,20 +52,7 @@
}
]
},
- {
- "type": "dict",
- "collapsible": true,
- "key": "ValidateMeshHasOverlappingUVs",
- "label": "ValidateMeshHasOverlappingUVs",
- "checkbox_key": "enabled",
- "children": [
- {
- "type": "boolean",
- "key": "enabled",
- "label": "Enabled"
- }
- ]
- },
+
{
"type": "dict",
"collapsible": true,
@@ -147,6 +72,169 @@
}
]
},
+ {
+ "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.
It will be checked against named group shader in your Validation regex.For example:
^.*(?P=<shader>.+)_GEO
"
+ },
+ {
+ "type": "path-widget",
+ "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": "ValidateMeshUVSetMap1",
+ "label": "ValidateMeshUVSetMap1",
+ "docstring": "Validate model's default uv set exists and is named 'map1'.
In Maya meshes by default have a uv set named 'map1' that cannot be deleted. It can be renamed, however,
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.
Even though a Model would extract without animCurves correctly this avoids getting different
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"
},
diff --git a/pype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json b/pype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json
new file mode 100644
index 0000000000..0e3770ac78
--- /dev/null
+++ b/pype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json
@@ -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"
+ }
+ ]
+ }
+ ]
+}
diff --git a/pype/settings/entities/schemas/projects_schema/schemas/template_create_plugin.json b/pype/settings/entities/schemas/projects_schema/schemas/template_create_plugin.json
new file mode 100644
index 0000000000..14d15e7840
--- /dev/null
+++ b/pype/settings/entities/schemas/projects_schema/schemas/template_create_plugin.json
@@ -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"
+ }
+ ]
+ }
+]
diff --git a/pype/settings/entities/schemas/projects_schema/schemas/template_loader_plugin.json b/pype/settings/entities/schemas/projects_schema/schemas/template_loader_plugin.json
new file mode 100644
index 0000000000..20dca6df17
--- /dev/null
+++ b/pype/settings/entities/schemas/projects_schema/schemas/template_loader_plugin.json
@@ -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": "representations",
+ "label": "Representations",
+ "object_type": "text"
+ }
+ ]
+ }
+]
diff --git a/pype/settings/entities/schemas/projects_schema/schemas/template_publish_plugin.json b/pype/settings/entities/schemas/projects_schema/schemas/template_publish_plugin.json
new file mode 100644
index 0000000000..88151f7534
--- /dev/null
+++ b/pype/settings/entities/schemas/projects_schema/schemas/template_publish_plugin.json
@@ -0,0 +1,30 @@
+[
+ {
+ "__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": "label",
+ "label": "{docstring}"
+ }
+ ]
+ }
+]
\ No newline at end of file
diff --git a/pype/settings/handlers.py b/pype/settings/handlers.py
index 0df4c98820..89f9645be7 100644
--- a/pype/settings/handlers.py
+++ b/pype/settings/handlers.py
@@ -10,7 +10,8 @@ import pype
from .constants import (
SYSTEM_SETTINGS_KEY,
PROJECT_SETTINGS_KEY,
- PROJECT_ANATOMY_KEY
+ PROJECT_ANATOMY_KEY,
+ LOCAL_SETTING_KEY
)
from .lib import load_json_file
@@ -103,6 +104,28 @@ class SettingsHandler:
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 SettingsFileHandler(SettingsHandler):
def __init__(self):
self.log = logging.getLogger("SettingsFileHandler")
@@ -495,3 +518,76 @@ class MongoSettingsHandler(SettingsHandler):
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 pype.lib import (
+ PypeMongoConnection,
+ get_local_site_id
+ )
+
+ if local_site_id is None:
+ local_site_id = get_local_site_id()
+ settings_collection = PypeMongoConnection.get_mongo_client()
+
+ # TODO prepare version of pype
+ # - pype version should define how are settings saved and loaded
+
+ # TODO modify to not use hardcoded keys
+ database_name = "pype"
+ 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,
+ "value": self.local_settings_cache.to_json_string()
+ },
+ 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()
diff --git a/pype/settings/lib.py b/pype/settings/lib.py
index dfc46e1a5a..feeeaf3813 100644
--- a/pype/settings/lib.py
+++ b/pype/settings/lib.py
@@ -2,6 +2,7 @@ import os
import json
import functools
import logging
+import platform
import copy
from .constants import (
M_OVERRIDEN_KEY,
@@ -11,7 +12,8 @@ from .constants import (
SYSTEM_SETTINGS_KEY,
PROJECT_SETTINGS_KEY,
- PROJECT_ANATOMY_KEY
+ PROJECT_ANATOMY_KEY,
+ DEFAULT_PROJECT_KEY
)
log = logging.getLogger(__name__)
@@ -32,6 +34,9 @@ _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)
@@ -43,6 +48,16 @@ def require_handler(func):
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
@@ -50,6 +65,11 @@ def create_settings_handler():
return MongoSettingsHandler()
+def create_local_settings_handler():
+ from .handlers import MongoLocalSettingsHandler
+ return MongoLocalSettingsHandler()
+
+
@require_handler
def save_studio_settings(data):
return _SETTINGS_HANDLER.save_studio_settings(data)
@@ -90,6 +110,16 @@ 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
@@ -309,6 +339,109 @@ def apply_overrides(source_data, override_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
+):
+ """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")
+ 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")
+ if not active_site:
+ active_site = default_locals.get("active_site")
+
+ if not active_site:
+ project_settings = get_project_settings(project_name)
+ active_site = (
+ project_settings
+ ["global"]
+ ["sync_server"]
+ ["config"]
+ ["active_site"]
+ )
+
+ # QUESTION should raise an exception?
+ if not active_site:
+ return
+
+ roots_locals = default_locals.get("roots", {}).get(active_site, {})
+ if project_name != DEFAULT_PROJECT_KEY:
+ roots_locals.update(
+ project_locals.get("roots", {}).get(active_site, {})
+ )
+
+ 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_system_settings(clear_metadata=True):
"""System settings with applied studio overrides."""
default_values = get_default_settings()[SYSTEM_SETTINGS_KEY]
@@ -316,6 +449,10 @@ def get_system_settings(clear_metadata=True):
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
@@ -343,6 +480,8 @@ def get_default_anatomy_settings(clear_metadata=True):
result[key] = value
if clear_metadata:
clear_metadata_from_settings(result)
+ local_settings = get_local_settings()
+ apply_local_settings_on_anatomy_settings(result, local_settings, None)
return result
@@ -368,6 +507,10 @@ def get_anatomy_settings(project_name, clear_metadata=True):
result[key] = value
if clear_metadata:
clear_metadata_from_settings(result)
+ local_settings = get_local_settings()
+ apply_local_settings_on_anatomy_settings(
+ result, local_settings, project_name
+ )
return result
diff --git a/pype/settings/local_settings.md b/pype/settings/local_settings.md
new file mode 100644
index 0000000000..fbb5cf3df1
--- /dev/null
+++ b/pype/settings/local_settings.md
@@ -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": {
+ "": {
+ "": {
+ "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": {
+ "": {
+ "active_site": "",
+ "remote_site": "",
+ "roots": {
+ "": {
+ "": ""
+ }
+ }
+ }
+ }
+}
+```
+
+## Final document
+```json
+{
+ "_id": "",
+ "site_id": "",
+ "general": {
+ "site_label": "MySite"
+ },
+ "applications": {
+ "": {
+ "": {
+ "executable": ""
+ }
+ }
+ },
+ "projects": {
+ "": {
+ "active_site": "",
+ "remote_site": "",
+ "roots": {
+ "": {
+ "": ""
+ }
+ }
+ }
+ }
+}
+```
diff --git a/pype/tools/settings/__init__.py b/pype/tools/settings/__init__.py
index 7bc54f9ab6..3f47d1c2c3 100644
--- a/pype/tools/settings/__init__.py
+++ b/pype/tools/settings/__init__.py
@@ -1,6 +1,6 @@
import sys
from Qt import QtWidgets, QtGui
-
+from .local_settings import LocalSettingsWindow
from .settings import (
style,
MainWidget,
@@ -33,5 +33,6 @@ __all__ = (
"style",
"MainWidget",
"ProjectListWidget",
+ "LocalSettingsWindow",
"main"
)
diff --git a/pype/tools/settings/local_settings/__init__.py b/pype/tools/settings/local_settings/__init__.py
new file mode 100644
index 0000000000..135a719a09
--- /dev/null
+++ b/pype/tools/settings/local_settings/__init__.py
@@ -0,0 +1,6 @@
+from .window import LocalSettingsWindow
+
+
+__all__ = (
+ "LocalSettingsWindow",
+)
diff --git a/pype/tools/settings/local_settings/apps_widget.py b/pype/tools/settings/local_settings/apps_widget.py
new file mode 100644
index 0000000000..d63cd6a834
--- /dev/null
+++ b/pype/tools/settings/local_settings/apps_widget.py
@@ -0,0 +1,205 @@
+import platform
+from Qt import QtWidgets
+from .widgets import (
+ Separator,
+ ExpandingWidget
+)
+from .constants import CHILD_OFFSET
+
+
+class AppVariantWidget(QtWidgets.QWidget):
+ exec_placeholder = "< Specific path for this machine >"
+
+ def __init__(self, group_label, variant_entity, parent):
+ super(AppVariantWidget, self).__init__(parent)
+
+ self.executable_input_widget = None
+
+ label = " ".join([group_label, variant_entity.label])
+
+ expading_widget = ExpandingWidget(label, self)
+ content_widget = QtWidgets.QWidget(expading_widget)
+ content_layout = QtWidgets.QVBoxLayout(content_widget)
+ content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0)
+
+ expading_widget.set_content_widget(content_widget)
+
+ # Add expanding widget to main layout
+ layout = QtWidgets.QHBoxLayout(self)
+ layout.setContentsMargins(0, 0, 0, 0)
+ layout.addWidget(expading_widget)
+
+ # TODO For celaction - not sure what is "Celaction publish" for
+ if not variant_entity["executables"].multiplatform:
+ warn_label = QtWidgets.QLabel(
+ "Application without multiplatform paths"
+ )
+ content_layout.addWidget(warn_label)
+ return
+
+ executable_input_widget = QtWidgets.QLineEdit(content_widget)
+ executable_input_widget.setPlaceholderText(self.exec_placeholder)
+ content_layout.addWidget(executable_input_widget)
+
+ self.executable_input_widget = executable_input_widget
+
+ studio_executables = (
+ variant_entity["executables"][platform.system().lower()]
+ )
+ if len(studio_executables) < 1:
+ return
+
+ content_layout.addWidget(Separator(parent=self))
+ content_layout.addWidget(
+ QtWidgets.QLabel("Studio paths:", self)
+ )
+
+ for item in studio_executables:
+ path_widget = QtWidgets.QLineEdit(content_widget)
+ path_widget.setText(item.value[0])
+ path_widget.setEnabled(False)
+ content_layout.addWidget(path_widget)
+
+ def update_local_settings(self, value):
+ if not self.executable_input_widget:
+ return
+
+ if not value:
+ value = {}
+ elif not isinstance(value, dict):
+ print("Got invalid value type {}. Expected {}".format(
+ type(value), dict
+ ))
+ value = {}
+
+ executable_path = value.get("executable")
+ if not executable_path:
+ executable_path = ""
+ elif isinstance(executable_path, list):
+ print("Got list in executable path so using first item as value")
+ executable_path = executable_path[0]
+
+ if not isinstance(executable_path, str):
+ executable_path = ""
+ print((
+ "Got invalid value type of app executable {}. Expected {}"
+ ).format(type(value), str))
+
+ self.executable_input_widget.setText(executable_path)
+
+ def settings_value(self):
+ if not self.executable_input_widget:
+ return None
+ value = self.executable_input_widget.text()
+ if not value:
+ return None
+ return {"executable": value}
+
+
+class AppGroupWidget(QtWidgets.QWidget):
+ def __init__(self, group_entity, parent):
+ super(AppGroupWidget, self).__init__(parent)
+
+ valid_variants = {}
+ for key, entity in group_entity["variants"].items():
+ if entity["enabled"].value:
+ valid_variants[key] = entity
+
+ group_label = group_entity.label
+ expading_widget = ExpandingWidget(group_label, self)
+ content_widget = QtWidgets.QWidget(expading_widget)
+ content_layout = QtWidgets.QVBoxLayout(content_widget)
+ content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0)
+
+ widgets_by_variant_name = {}
+ for variant_name, variant_entity in valid_variants.items():
+ variant_widget = AppVariantWidget(
+ group_label, variant_entity, content_widget
+ )
+ widgets_by_variant_name[variant_name] = variant_widget
+ content_layout.addWidget(variant_widget)
+
+ expading_widget.set_content_widget(content_widget)
+
+ layout = QtWidgets.QHBoxLayout(self)
+ layout.setContentsMargins(0, 0, 0, 0)
+ layout.addWidget(expading_widget)
+
+ self.widgets_by_variant_name = widgets_by_variant_name
+
+ def update_local_settings(self, value):
+ if not value:
+ value = {}
+
+ for variant_name, widget in self.widgets_by_variant_name.items():
+ widget.update_local_settings(value.get(variant_name))
+
+ def settings_value(self):
+ output = {}
+ for variant_name, widget in self.widgets_by_variant_name.items():
+ value = widget.settings_value()
+ if value:
+ output[variant_name] = value
+
+ if not output:
+ return None
+ return output
+
+
+class LocalApplicationsWidgets(QtWidgets.QWidget):
+ def __init__(self, system_settings_entity, parent):
+ super(LocalApplicationsWidgets, self).__init__(parent)
+
+ self.widgets_by_group_name = {}
+ self.system_settings_entity = system_settings_entity
+
+ layout = QtWidgets.QVBoxLayout(self)
+ layout.setContentsMargins(0, 0, 0, 0)
+
+ self.content_layout = layout
+
+ def _reset_app_widgets(self):
+ while self.content_layout.count() > 0:
+ item = self.content_layout.itemAt(0)
+ item.widget().hide()
+ self.content_layout.removeItem(item)
+ self.widgets_by_group_name.clear()
+
+ for key, entity in self.system_settings_entity["applications"].items():
+ # Filter not enabled app groups
+ if not entity["enabled"].value:
+ continue
+
+ # Check if has enabled any variant
+ enabled_variant = False
+ for variant_entity in entity["variants"].values():
+ if variant_entity["enabled"].value:
+ enabled_variant = True
+ break
+
+ if not enabled_variant:
+ continue
+
+ # Create App group specific widget and store it by the key
+ group_widget = AppGroupWidget(entity, self)
+ self.widgets_by_group_name[key] = group_widget
+ self.content_layout.addWidget(group_widget)
+
+ def update_local_settings(self, value):
+ if not value:
+ value = {}
+
+ self._reset_app_widgets()
+
+ for group_name, widget in self.widgets_by_group_name.items():
+ widget.update_local_settings(value.get(group_name))
+
+ def settings_value(self):
+ output = {}
+ for group_name, widget in self.widgets_by_group_name.items():
+ value = widget.settings_value()
+ if value:
+ output[group_name] = value
+ if not output:
+ return None
+ return output
diff --git a/pype/tools/settings/local_settings/constants.py b/pype/tools/settings/local_settings/constants.py
new file mode 100644
index 0000000000..83c45afba8
--- /dev/null
+++ b/pype/tools/settings/local_settings/constants.py
@@ -0,0 +1,32 @@
+# Action labels
+LABEL_REMOVE_DEFAULT = "Remove from default"
+LABEL_ADD_DEFAULT = "Add to default"
+LABEL_REMOVE_PROJECT = "Remove from project"
+LABEL_ADD_PROJECT = "Add to project"
+LABEL_DISCARD_CHANGES = "Discard changes"
+
+# Local setting contants
+# TODO move to settings constants
+LOCAL_GENERAL_KEY = "general"
+LOCAL_PROJECTS_KEY = "projects"
+LOCAL_APPS_KEY = "applications"
+
+# Roots key constant
+LOCAL_ROOTS_KEY = "roots"
+
+# Child offset in expandable widget
+CHILD_OFFSET = 15
+
+__all__ = (
+ "LABEL_REMOVE_DEFAULT",
+ "LABEL_ADD_DEFAULT",
+ "LABEL_REMOVE_PROJECT",
+ "LABEL_ADD_PROJECT",
+ "LABEL_DISCARD_CHANGES",
+
+ "LOCAL_GENERAL_KEY",
+ "LOCAL_PROJECTS_KEY",
+ "LOCAL_APPS_KEY",
+
+ "LOCAL_ROOTS_KEY"
+)
diff --git a/pype/tools/settings/local_settings/general_widget.py b/pype/tools/settings/local_settings/general_widget.py
new file mode 100644
index 0000000000..7732157122
--- /dev/null
+++ b/pype/tools/settings/local_settings/general_widget.py
@@ -0,0 +1,32 @@
+from Qt import QtWidgets
+
+
+class LocalGeneralWidgets(QtWidgets.QWidget):
+ def __init__(self, parent):
+ super(LocalGeneralWidgets, self).__init__(parent)
+
+ local_site_name_input = QtWidgets.QLineEdit(self)
+
+ layout = QtWidgets.QFormLayout(self)
+ layout.setContentsMargins(0, 0, 0, 0)
+
+ layout.addRow("Local site label", local_site_name_input)
+
+ self.local_site_name_input = local_site_name_input
+
+ def update_local_settings(self, value):
+ site_label = ""
+ if value:
+ site_label = value.get("site_label", site_label)
+ self.local_site_name_input.setText(site_label)
+
+ def settings_value(self):
+ # Add changed
+ # If these have changed then
+ output = {}
+ local_site_name = self.local_site_name_input.text()
+ if local_site_name:
+ output["site_label"] = local_site_name
+ # Do not return output yet since we don't have mechanism to save or
+ # load these data through api calls
+ return output
diff --git a/pype/tools/settings/local_settings/mongo_widget.py b/pype/tools/settings/local_settings/mongo_widget.py
new file mode 100644
index 0000000000..c6f6ab1591
--- /dev/null
+++ b/pype/tools/settings/local_settings/mongo_widget.py
@@ -0,0 +1,80 @@
+import os
+import sys
+import traceback
+
+from Qt import QtWidgets
+from pymongo.errors import ServerSelectionTimeoutError
+
+from pype.api import change_pype_mongo_url
+
+
+class PypeMongoWidget(QtWidgets.QWidget):
+ def __init__(self, parent):
+ super(PypeMongoWidget, self).__init__(parent)
+
+ # Warning label
+ warning_label = QtWidgets.QLabel((
+ "WARNING: Requires restart. Change of Pype Mongo requires to"
+ " restart of all running Pype processes and process using Pype"
+ " (Including this)."
+ "\n- all changes in different categories won't be saved."
+ ), self)
+ warning_label.setStyleSheet("font-weight: bold;")
+
+ # Label
+ mongo_url_label = QtWidgets.QLabel("Pype Mongo URL", self)
+
+ # Input
+ mongo_url_input = QtWidgets.QLineEdit(self)
+ mongo_url_input.setPlaceholderText("< Pype Mongo URL >")
+ mongo_url_input.setText(os.environ["PYPE_MONGO"])
+
+ # Confirm button
+ mongo_url_change_btn = QtWidgets.QPushButton("Confirm Change", self)
+
+ layout = QtWidgets.QGridLayout(self)
+ layout.setContentsMargins(0, 0, 0, 0)
+ layout.addWidget(warning_label, 0, 0, 1, 3)
+ layout.addWidget(mongo_url_label, 1, 0)
+ layout.addWidget(mongo_url_input, 1, 1)
+ layout.addWidget(mongo_url_change_btn, 1, 2)
+
+ mongo_url_change_btn.clicked.connect(self._on_confirm_click)
+
+ self.mongo_url_input = mongo_url_input
+
+ def _on_confirm_click(self):
+ value = self.mongo_url_input.text()
+
+ dialog = QtWidgets.QMessageBox(self)
+
+ title = "Pype mongo changed"
+ message = (
+ "Pype mongo url was successfully changed. Restart Pype please."
+ )
+ details = None
+
+ try:
+ change_pype_mongo_url(value)
+ except Exception as exc:
+ if isinstance(exc, ServerSelectionTimeoutError):
+ error_message = (
+ "Connection timeout passed."
+ " Probably can't connect to the Mongo server."
+ )
+ else:
+ error_message = str(exc)
+
+ title = "Pype mongo change failed"
+ # TODO catch exception message more gracefully
+ message = (
+ "Pype mongo change was not successful."
+ " Full traceback can be found in details section.\n\n"
+ "Error message:\n{}"
+ ).format(error_message)
+ details = "\n".join(traceback.format_exception(*sys.exc_info()))
+ dialog.setWindowTitle(title)
+ dialog.setText(message)
+ if details:
+ dialog.setDetailedText(details)
+ dialog.exec_()
diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py
new file mode 100644
index 0000000000..28765155c2
--- /dev/null
+++ b/pype/tools/settings/local_settings/projects_widget.py
@@ -0,0 +1,731 @@
+import platform
+import copy
+from Qt import QtWidgets, QtCore, QtGui
+from pype.tools.settings.settings import ProjectListWidget
+from pype.settings.constants import (
+ PROJECT_ANATOMY_KEY,
+ DEFAULT_PROJECT_KEY
+)
+from .widgets import (
+ SpacerWidget,
+ ProxyLabelWidget
+)
+from .constants import (
+ LABEL_REMOVE_DEFAULT,
+ LABEL_ADD_DEFAULT,
+ LABEL_REMOVE_PROJECT,
+ LABEL_ADD_PROJECT,
+ LABEL_DISCARD_CHANGES,
+ LOCAL_ROOTS_KEY
+)
+
+NOT_SET = type("NOT_SET", (), {})()
+
+
+def get_active_sites(project_settings):
+ global_entity = project_settings["project_settings"]["global"]
+ sites_entity = global_entity["sync_server"]["sites"]
+ return tuple(sites_entity.keys())
+
+
+class _ProjectListWidget(ProjectListWidget):
+ def on_item_clicked(self, new_index):
+ new_project_name = new_index.data(QtCore.Qt.DisplayRole)
+ if new_project_name is None:
+ return
+
+ if self.current_project == new_project_name:
+ return
+
+ self.select_project(new_project_name)
+ self.current_project = new_project_name
+ self.project_changed.emit()
+
+
+class RootInputWidget(QtWidgets.QWidget):
+ def __init__(
+ self,
+ local_project_settings,
+ local_project_settings_orig,
+ platform_root_entity,
+ root_name,
+ project_name,
+ site_name,
+ parent
+ ):
+ super(RootInputWidget, self).__init__(parent)
+
+ self.local_project_settings = local_project_settings
+ self.local_project_settings_orig = local_project_settings_orig
+ self.platform_root_entity = platform_root_entity
+ self.root_name = root_name
+ self.site_name = site_name
+ self.project_name = project_name
+
+ self.origin_value = self._get_site_value_for_project(
+ self.project_name, self.local_project_settings_orig
+ ) or ""
+
+ is_default_project = bool(project_name == DEFAULT_PROJECT_KEY)
+
+ default_input_value = self._get_site_value_for_project(
+ DEFAULT_PROJECT_KEY
+ )
+ if is_default_project:
+ input_value = default_input_value
+ project_value = None
+ else:
+ input_value = self._get_site_value_for_project(self.project_name)
+ project_value = input_value
+
+ # Placeholder
+ placeholder = None
+ if not is_default_project:
+ placeholder = default_input_value
+
+ if not placeholder:
+ placeholder = platform_root_entity.value
+
+ key_label = ProxyLabelWidget(
+ root_name,
+ self._mouse_release_callback,
+ self
+ )
+ value_input = QtWidgets.QLineEdit(self)
+ value_input.setPlaceholderText("< {} >".format(placeholder))
+
+ # Root value
+ if input_value:
+ value_input.setText(input_value)
+
+ value_input.textChanged.connect(self._on_value_change)
+
+ root_layout = QtWidgets.QHBoxLayout(self)
+ root_layout.addWidget(key_label)
+ root_layout.addWidget(value_input)
+
+ self.value_input = value_input
+ self.label_widget = key_label
+
+ self.studio_value = platform_root_entity.value
+ self.default_value = default_input_value
+ self.project_value = project_value
+ self.placeholder_value = placeholder
+
+ self._update_style()
+
+ def is_modified(self):
+ return self.origin_value != self.value_input.text()
+
+ def _mouse_release_callback(self, event):
+ if event.button() != QtCore.Qt.RightButton:
+ return
+ self._show_actions()
+ event.accept()
+
+ def _get_style_state(self):
+ if self.project_name is None:
+ return ""
+
+ if self.is_modified():
+ return "modified"
+
+ current_value = self.value_input.text()
+ if self.project_name == DEFAULT_PROJECT_KEY:
+ if current_value:
+ return "studio"
+ else:
+ if current_value:
+ return "overriden"
+
+ studio_value = self._get_site_value_for_project(
+ DEFAULT_PROJECT_KEY
+ )
+ if studio_value:
+ return "studio"
+ return ""
+
+ def _update_style(self):
+ state = self._get_style_state()
+
+ self.value_input.setProperty("input-state", state)
+ self.value_input.style().polish(self.value_input)
+
+ self.label_widget.set_label_property("state", state)
+
+ def _remove_from_local(self):
+ self.value_input.setText("")
+ self._update_style()
+
+ def _add_to_local(self):
+ self.value_input.setText(self.placeholder_value)
+ self._update_style()
+
+ def discard_changes(self):
+ self.value_input.setText(self.origin_value)
+ self._update_style()
+
+ def _show_actions(self):
+ if self.project_name is None:
+ return
+
+ menu = QtWidgets.QMenu(self)
+ actions_mapping = {}
+
+ if self.project_name == DEFAULT_PROJECT_KEY:
+ remove_label = LABEL_REMOVE_DEFAULT
+ add_label = LABEL_ADD_DEFAULT
+ else:
+ remove_label = LABEL_REMOVE_PROJECT
+ add_label = LABEL_ADD_PROJECT
+
+ if self.value_input.text():
+ action = QtWidgets.QAction(remove_label)
+ callback = self._remove_from_local
+ else:
+ action = QtWidgets.QAction(add_label)
+ callback = self._add_to_local
+
+ actions_mapping[action] = callback
+ menu.addAction(action)
+
+ if self.is_modified():
+ discard_changes_action = QtWidgets.QAction(LABEL_DISCARD_CHANGES)
+ actions_mapping[discard_changes_action] = self.discard_changes
+ menu.addAction(discard_changes_action)
+
+ result = menu.exec_(QtGui.QCursor.pos())
+ if result:
+ to_run = actions_mapping[result]
+ if to_run:
+ to_run()
+
+ def _get_site_value_for_project(self, project_name, data=None):
+ if data is None:
+ data = self.local_project_settings
+ project_values = data.get(project_name)
+ site_value = {}
+ if project_values:
+ root_value = project_values.get(LOCAL_ROOTS_KEY)
+ if root_value:
+ site_value = root_value.get(self.site_name) or {}
+ return site_value.get(self.root_name)
+
+ def _on_value_change(self):
+ value = self.value_input.text()
+ data = self.local_project_settings
+ for key in (self.project_name, LOCAL_ROOTS_KEY, self.site_name):
+ if key not in data:
+ data[key] = {}
+ data = data[key]
+ data[self.root_name] = value
+ self._update_style()
+
+
+class RootsWidget(QtWidgets.QWidget):
+ def __init__(self, project_settings, parent):
+ super(RootsWidget, self).__init__(parent)
+
+ self.project_settings = project_settings
+ self.site_widgets = []
+ self.local_project_settings = None
+ self.local_project_settings_orig = None
+ self._project_name = None
+
+ self.content_layout = QtWidgets.QVBoxLayout(self)
+
+ def _clear_widgets(self):
+ while self.content_layout.count():
+ item = self.content_layout.itemAt(0)
+ item.widget().hide()
+ self.content_layout.removeItem(item)
+ self.site_widgets = []
+
+ def refresh(self):
+ self._clear_widgets()
+
+ if self._project_name is None:
+ return
+
+ roots_entity = (
+ self.project_settings[PROJECT_ANATOMY_KEY][LOCAL_ROOTS_KEY]
+ )
+ # Site label
+ for site_name in get_active_sites(self.project_settings):
+ site_widget = QtWidgets.QWidget(self)
+ site_layout = QtWidgets.QVBoxLayout(site_widget)
+
+ site_label = QtWidgets.QLabel(site_name, site_widget)
+
+ site_layout.addWidget(site_label)
+
+ # Root inputs
+ for root_name, path_entity in roots_entity.items():
+ platform_entity = path_entity[platform.system().lower()]
+ root_widget = RootInputWidget(
+ self.local_project_settings,
+ self.local_project_settings_orig,
+ platform_entity,
+ root_name,
+ self._project_name,
+ site_name,
+ site_widget
+ )
+
+ site_layout.addWidget(root_widget)
+
+ self.site_widgets.append(site_widget)
+ self.content_layout.addWidget(site_widget)
+
+ # Add spacer so other widgets are squeezed to top
+ self.content_layout.addWidget(SpacerWidget(self), 1)
+
+ def update_local_settings(self, local_project_settings):
+ self.local_project_settings = local_project_settings
+ self.local_project_settings_orig = copy.deepcopy(
+ dict(local_project_settings)
+ )
+
+ def change_project(self, project_name):
+ self._project_name = project_name
+ self.refresh()
+
+
+class _SiteCombobox(QtWidgets.QWidget):
+ input_label = None
+
+ def __init__(self, project_settings, parent):
+ super(_SiteCombobox, self).__init__(parent)
+ self.project_settings = project_settings
+
+ self.local_project_settings = None
+ self.local_project_settings_orig = None
+ self.project_name = None
+
+ self.default_override_value = None
+ self.project_override_value = None
+
+ label_widget = ProxyLabelWidget(
+ self.input_label,
+ self._mouse_release_callback,
+ self
+ )
+ combobox_input = QtWidgets.QComboBox(self)
+
+ main_layout = QtWidgets.QHBoxLayout(self)
+ main_layout.addWidget(label_widget)
+ main_layout.addWidget(combobox_input)
+
+ combobox_input.currentIndexChanged.connect(self._on_index_change)
+ self.label_widget = label_widget
+ self.combobox_input = combobox_input
+
+ def _set_current_text(self, text):
+ index = None
+ if text:
+ idx = self.combobox_input.findText(text)
+ if idx >= 0:
+ index = idx
+
+ if index is not None:
+ self.combobox_input.setCurrentIndex(index)
+ return True
+ return False
+
+ def is_modified(self, current_value=NOT_SET, orig_value=NOT_SET):
+ if current_value is NOT_SET:
+ current_value = self._get_local_settings_item(self.project_name)
+ if orig_value is NOT_SET:
+ orig_value = self._get_local_settings_item(
+ self.project_name, self.local_project_settings_orig
+ )
+ if current_value and orig_value:
+ modified = current_value != orig_value
+ elif not current_value and not orig_value:
+ modified = False
+ else:
+ modified = True
+ return modified
+
+ def _get_style_state(self):
+ if self.project_name is None:
+ return ""
+
+ current_value = self._get_local_settings_item(self.project_name)
+ orig_value = self._get_local_settings_item(
+ self.project_name, self.local_project_settings_orig
+ )
+
+ if self.is_modified(current_value, orig_value):
+ return "modified"
+
+ if self.project_name == DEFAULT_PROJECT_KEY:
+ if current_value:
+ return "studio"
+ else:
+ if current_value:
+ return "overriden"
+
+ studio_value = self._get_local_settings_item(DEFAULT_PROJECT_KEY)
+ if studio_value:
+ return "studio"
+ return ""
+
+ def _update_style(self):
+ state = self._get_style_state()
+
+ self.combobox_input.setProperty("input-state", state)
+ self.combobox_input.style().polish(self.combobox_input)
+
+ self.label_widget.set_label_property("state", state)
+
+ def _mouse_release_callback(self, event):
+ if event.button() != QtCore.Qt.RightButton:
+ return
+ self._show_actions()
+
+ def _remove_from_local(self):
+ settings_value = self._get_value_from_project_settings()
+ combobox_value = None
+ if self.project_name == DEFAULT_PROJECT_KEY:
+ combobox_value = self._get_local_settings_item(DEFAULT_PROJECT_KEY)
+ if combobox_value:
+ idx = self.combobox_input.findText(combobox_value)
+ if idx < 0:
+ combobox_value = None
+
+ if not combobox_value:
+ combobox_value = settings_value
+
+ if combobox_value:
+ _project_name = self.project_name
+ self.project_name = None
+ self._set_current_text(combobox_value)
+ self.project_name = _project_name
+
+ self._set_local_settings_value("")
+ self._update_style()
+
+ def _add_to_local(self):
+ self._set_local_settings_value(self.current_text())
+ self._update_style()
+
+ def discard_changes(self):
+ orig_value = self._get_local_settings_item(
+ self.project_name, self.local_project_settings_orig
+ )
+ self._set_current_text(orig_value)
+
+ def _show_actions(self):
+ if self.project_name is None:
+ return
+
+ menu = QtWidgets.QMenu(self)
+ actions_mapping = {}
+
+ if self.project_name == DEFAULT_PROJECT_KEY:
+ remove_label = LABEL_REMOVE_DEFAULT
+ add_label = LABEL_ADD_DEFAULT
+ else:
+ remove_label = LABEL_REMOVE_PROJECT
+ add_label = LABEL_ADD_PROJECT
+
+ has_value = self._get_local_settings_item(self.project_name)
+ if has_value:
+ action = QtWidgets.QAction(remove_label)
+ callback = self._remove_from_local
+ else:
+ action = QtWidgets.QAction(add_label)
+ callback = self._add_to_local
+
+ actions_mapping[action] = callback
+ menu.addAction(action)
+
+ if self.is_modified():
+ discard_changes_action = QtWidgets.QAction(LABEL_DISCARD_CHANGES)
+ actions_mapping[discard_changes_action] = self.discard_changes
+ menu.addAction(discard_changes_action)
+
+ result = menu.exec_(QtGui.QCursor.pos())
+ if result:
+ to_run = actions_mapping[result]
+ if to_run:
+ to_run()
+
+ def update_local_settings(self, local_project_settings):
+ self.local_project_settings = local_project_settings
+ self.local_project_settings_orig = copy.deepcopy(
+ dict(local_project_settings)
+ )
+
+ def current_text(self):
+ return self.combobox_input.currentText()
+
+ def change_project(self, project_name):
+ self.default_override_value = None
+ self.project_override_value = None
+
+ self.project_name = None
+ self.combobox_input.clear()
+ if project_name is None:
+ self._update_style()
+ return
+
+ is_default_project = bool(project_name == DEFAULT_PROJECT_KEY)
+ site_items = self._get_project_sites()
+ self.combobox_input.addItems(site_items)
+
+ default_item = self._get_local_settings_item(DEFAULT_PROJECT_KEY)
+ if is_default_project:
+ project_item = None
+ else:
+ project_item = self._get_local_settings_item(project_name)
+
+ index = None
+ if project_item:
+ idx = self.combobox_input.findText(project_item)
+ if idx >= 0:
+ self.project_override_value = project_item
+ index = idx
+
+ if default_item:
+ idx = self.combobox_input.findText(default_item)
+ if idx >= 0:
+ self.default_override_value = default_item
+ if index is None:
+ index = idx
+
+ if index is None:
+ settings_value = self._get_value_from_project_settings()
+ idx = self.combobox_input.findText(settings_value)
+ if idx >= 0:
+ index = idx
+
+ if index is not None:
+ self.combobox_input.setCurrentIndex(index)
+
+ self.project_name = project_name
+ self._update_style()
+
+ def _on_index_change(self):
+ if self.project_name is None:
+ return
+
+ self._set_local_settings_value(self.current_text())
+ self._update_style()
+
+ def _set_local_settings_value(self, value):
+ raise NotImplementedError(
+ "{} `_set_local_settings_value` not implemented".format(
+ self.__class__.__name__
+ )
+ )
+
+ def _get_project_sites(self):
+ raise NotImplementedError(
+ "{} `_get_project_sites` not implemented".format(
+ self.__class__.__name__
+ )
+ )
+
+ def _get_local_settings_item(self, project_name=None, data=None):
+ raise NotImplementedError(
+ "{}`_get_local_settings_item` not implemented".format(
+ self.__class__.__name__
+ )
+ )
+
+ def _get_value_from_project_settings(self):
+ raise NotImplementedError(
+ "{}`_get_value_from_project_settings` not implemented".format(
+ self.__class__.__name__
+ )
+ )
+
+
+class AciveSiteCombo(_SiteCombobox):
+ input_label = "Active site"
+
+ def _get_project_sites(self):
+ return get_active_sites(self.project_settings)
+
+ def _get_local_settings_item(self, project_name=None, data=None):
+ if project_name is None:
+ project_name = self.project_name
+
+ if data is None:
+ data = self.local_project_settings
+ project_values = data.get(project_name)
+ value = None
+ if project_values:
+ value = project_values.get("active_site")
+ return value
+
+ def _get_value_from_project_settings(self):
+ global_entity = self.project_settings["project_settings"]["global"]
+ return global_entity["sync_server"]["config"]["active_site"].value
+
+ def _set_local_settings_value(self, value):
+ if self.project_name not in self.local_project_settings:
+ self.local_project_settings[self.project_name] = {}
+ self.local_project_settings[self.project_name]["active_site"] = value
+
+
+class RemoteSiteCombo(_SiteCombobox):
+ input_label = "Remote site"
+
+ def _get_project_sites(self):
+ global_entity = self.project_settings["project_settings"]["global"]
+ sites_entity = global_entity["sync_server"]["sites"]
+ return tuple(sites_entity.keys())
+
+ def _get_local_settings_item(self, project_name=None, data=None):
+ if project_name is None:
+ project_name = self.project_name
+ if data is None:
+ data = self.local_project_settings
+ project_values = data.get(project_name)
+ value = None
+ if project_values:
+ value = project_values.get("remote_site")
+ return value
+
+ def _get_value_from_project_settings(self):
+ global_entity = self.project_settings["project_settings"]["global"]
+ return global_entity["sync_server"]["config"]["remote_site"].value
+
+ def _set_local_settings_value(self, value):
+ if self.project_name not in self.local_project_settings:
+ self.local_project_settings[self.project_name] = {}
+ self.local_project_settings[self.project_name]["remote_site"] = value
+
+
+class RootSiteWidget(QtWidgets.QWidget):
+ def __init__(self, project_settings, parent):
+ self._parent_widget = parent
+ super(RootSiteWidget, self).__init__(parent)
+
+ self.project_settings = project_settings
+ self._project_name = None
+
+ sites_widget = QtWidgets.QWidget(self)
+
+ active_site_widget = AciveSiteCombo(project_settings, sites_widget)
+ remote_site_widget = RemoteSiteCombo(project_settings, sites_widget)
+
+ sites_layout = QtWidgets.QHBoxLayout(sites_widget)
+ sites_layout.setContentsMargins(0, 0, 0, 0)
+ sites_layout.addWidget(active_site_widget)
+ sites_layout.addWidget(remote_site_widget)
+ sites_layout.addWidget(SpacerWidget(self), 1)
+
+ roots_widget = RootsWidget(project_settings, self)
+
+ main_layout = QtWidgets.QVBoxLayout(self)
+ main_layout.addWidget(sites_widget)
+ main_layout.addWidget(roots_widget)
+ main_layout.addWidget(SpacerWidget(self), 1)
+
+ self.active_site_widget = active_site_widget
+ self.remote_site_widget = remote_site_widget
+ self.roots_widget = roots_widget
+
+ def _active_site_values(self):
+ global_entity = self.project_settings["project_settings"]["global"]
+ sites_entity = global_entity["sync_server"]["sites"]
+ return tuple(sites_entity.keys())
+
+ def _remote_site_values(self):
+ global_entity = self.project_settings["project_settings"]["global"]
+ sites_entity = global_entity["sync_server"]["sites"]
+ return tuple(sites_entity.keys())
+
+ def update_local_settings(self, local_project_settings):
+ self.local_project_settings = local_project_settings
+ self.active_site_widget.update_local_settings(local_project_settings)
+ self.remote_site_widget.update_local_settings(local_project_settings)
+ self.roots_widget.update_local_settings(local_project_settings)
+ project_name = self._project_name
+ if project_name is None:
+ project_name = DEFAULT_PROJECT_KEY
+
+ self.change_project(project_name)
+
+ def change_project(self, project_name):
+ self._project_name = project_name
+ # Set roots project to None so all changes below are ignored
+ self.roots_widget.change_project(None)
+
+ # Aply changes in site comboboxes
+ self.active_site_widget.change_project(project_name)
+ self.remote_site_widget.change_project(project_name)
+
+ # Change project name in roots widget
+ self.roots_widget.change_project(project_name)
+
+
+class ProjectValue(dict):
+ pass
+
+
+class ProjectSettingsWidget(QtWidgets.QWidget):
+ def __init__(self, project_settings, parent):
+ super(ProjectSettingsWidget, self).__init__(parent)
+
+ self.local_project_settings = {}
+
+ projects_widget = _ProjectListWidget(self)
+ roos_site_widget = RootSiteWidget(project_settings, self)
+
+ main_layout = QtWidgets.QHBoxLayout(self)
+ main_layout.setContentsMargins(0, 0, 0, 0)
+ main_layout.addWidget(projects_widget, 0)
+ main_layout.addWidget(roos_site_widget, 1)
+
+ projects_widget.project_changed.connect(self._on_project_change)
+
+ self.project_settings = project_settings
+
+ self.projects_widget = projects_widget
+ self.roos_site_widget = roos_site_widget
+
+ def project_name(self):
+ return self.projects_widget.project_name()
+
+ def _on_project_change(self):
+ project_name = self.project_name()
+ self.project_settings.change_project(project_name)
+ if project_name is None:
+ project_name = DEFAULT_PROJECT_KEY
+ self.roos_site_widget.change_project(project_name)
+
+ def update_local_settings(self, value):
+ if not value:
+ value = {}
+ self.local_project_settings = ProjectValue(value)
+
+ self.roos_site_widget.update_local_settings(
+ self.local_project_settings
+ )
+
+ self.projects_widget.refresh()
+
+ def _clear_value(self, value):
+ if not value:
+ return None
+
+ if not isinstance(value, dict):
+ return value
+
+ output = {}
+ for _key, _value in value.items():
+ _modified_value = self._clear_value(_value)
+ if _modified_value:
+ output[_key] = _modified_value
+ return output
+
+ def settings_value(self):
+ output = self._clear_value(self.local_project_settings)
+ if not output:
+ return None
+ return output
diff --git a/pype/tools/settings/local_settings/widgets.py b/pype/tools/settings/local_settings/widgets.py
new file mode 100644
index 0000000000..1b077f93be
--- /dev/null
+++ b/pype/tools/settings/local_settings/widgets.py
@@ -0,0 +1,59 @@
+from Qt import QtWidgets, QtCore
+from pype.tools.settings.settings.widgets.widgets import (
+ ExpandingWidget,
+ SpacerWidget
+)
+
+
+class Separator(QtWidgets.QFrame):
+ def __init__(self, height=None, parent=None):
+ super(Separator, self).__init__(parent)
+ if height is None:
+ height = 2
+
+ splitter_item = QtWidgets.QWidget(self)
+ splitter_item.setStyleSheet("background-color: #21252B;")
+ splitter_item.setMinimumHeight(height)
+ splitter_item.setMaximumHeight(height)
+
+ layout = QtWidgets.QHBoxLayout(self)
+ layout.setContentsMargins(5, 5, 5, 5)
+ layout.addWidget(splitter_item)
+
+
+class ProxyLabelWidget(QtWidgets.QWidget):
+ def __init__(self, label, mouse_release_callback, parent=None):
+ super(ProxyLabelWidget, self).__init__(parent)
+
+ self.mouse_release_callback = mouse_release_callback
+
+ layout = QtWidgets.QVBoxLayout(self)
+ layout.setContentsMargins(0, 0, 0, 0)
+ layout.setSpacing(0)
+
+ label_widget = QtWidgets.QLabel(label, self)
+ layout.addWidget(label_widget)
+
+ self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
+
+ self.label_widget = label_widget
+
+ def setText(self, text):
+ self.label_widget.setText(text)
+
+ def set_label_property(self, *args, **kwargs):
+ self.label_widget.setProperty(*args, **kwargs)
+ self.label_widget.style().polish(self.label_widget)
+
+ def mouseReleaseEvent(self, event):
+ if self.mouse_release_callback:
+ return self.mouse_release_callback(event)
+ return super(ProxyLabelWidget, self).mouseReleaseEvent(event)
+
+
+__all__ = (
+ "ExpandingWidget",
+ "SpacerWidget",
+ "Separator",
+ "SpacerWidget"
+)
diff --git a/pype/tools/settings/local_settings/window.py b/pype/tools/settings/local_settings/window.py
new file mode 100644
index 0000000000..87a276c78c
--- /dev/null
+++ b/pype/tools/settings/local_settings/window.py
@@ -0,0 +1,204 @@
+import logging
+from Qt import QtWidgets, QtGui
+
+from ..settings import style
+
+from pype.settings.lib import (
+ get_local_settings,
+ save_local_settings
+)
+from pype.api import (
+ SystemSettings,
+ ProjectSettings
+)
+
+from .widgets import (
+ SpacerWidget,
+ ExpandingWidget
+)
+from .mongo_widget import PypeMongoWidget
+from .general_widget import LocalGeneralWidgets
+from .apps_widget import LocalApplicationsWidgets
+from .projects_widget import ProjectSettingsWidget
+
+from .constants import (
+ CHILD_OFFSET,
+ LOCAL_GENERAL_KEY,
+ LOCAL_PROJECTS_KEY,
+ LOCAL_APPS_KEY
+)
+
+log = logging.getLogger(__name__)
+
+
+class LocalSettingsWidget(QtWidgets.QWidget):
+ def __init__(self, parent=None):
+ super(LocalSettingsWidget, self).__init__(parent)
+
+ self.system_settings = SystemSettings()
+ self.project_settings = ProjectSettings()
+
+ self.main_layout = QtWidgets.QVBoxLayout(self)
+
+ self.pype_mongo_widget = None
+ self.general_widget = None
+ self.apps_widget = None
+ self.projects_widget = None
+
+ self._create_pype_mongo_ui()
+ self._create_general_ui()
+ self._create_app_ui()
+ self._create_project_ui()
+
+ # Add spacer to main layout
+ self.main_layout.addWidget(SpacerWidget(self), 1)
+
+ def _create_pype_mongo_ui(self):
+ pype_mongo_expand_widget = ExpandingWidget("Pype Mongo URL", self)
+ pype_mongo_content = QtWidgets.QWidget(self)
+ pype_mongo_layout = QtWidgets.QVBoxLayout(pype_mongo_content)
+ pype_mongo_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0)
+ pype_mongo_expand_widget.set_content_widget(pype_mongo_content)
+
+ pype_mongo_widget = PypeMongoWidget(self)
+ pype_mongo_layout.addWidget(pype_mongo_widget)
+
+ self.main_layout.addWidget(pype_mongo_expand_widget)
+
+ self.pype_mongo_widget = pype_mongo_widget
+
+ def _create_general_ui(self):
+ # General
+ general_expand_widget = ExpandingWidget("General", self)
+
+ general_content = QtWidgets.QWidget(self)
+ general_layout = QtWidgets.QVBoxLayout(general_content)
+ general_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0)
+ general_expand_widget.set_content_widget(general_content)
+
+ general_widget = LocalGeneralWidgets(general_content)
+ general_layout.addWidget(general_widget)
+
+ self.main_layout.addWidget(general_expand_widget)
+
+ self.general_widget = general_widget
+
+ def _create_app_ui(self):
+ # Applications
+ app_expand_widget = ExpandingWidget("Applications", self)
+
+ app_content = QtWidgets.QWidget(self)
+ app_layout = QtWidgets.QVBoxLayout(app_content)
+ app_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0)
+ app_expand_widget.set_content_widget(app_content)
+
+ app_widget = LocalApplicationsWidgets(
+ self.system_settings, app_content
+ )
+ app_layout.addWidget(app_widget)
+
+ self.main_layout.addWidget(app_expand_widget)
+
+ self.app_widget = app_widget
+
+ def _create_project_ui(self):
+ project_expand_widget = ExpandingWidget("Project settings", self)
+ project_content = QtWidgets.QWidget(self)
+ project_layout = QtWidgets.QVBoxLayout(project_content)
+ project_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0)
+ project_expand_widget.set_content_widget(project_content)
+
+ projects_widget = ProjectSettingsWidget(self.project_settings, self)
+ project_layout.addWidget(projects_widget)
+
+ self.main_layout.addWidget(project_expand_widget)
+
+ self.projects_widget = projects_widget
+
+ def update_local_settings(self, value):
+ if not value:
+ value = {}
+
+ self.system_settings.reset()
+ self.project_settings.reset()
+
+ self.general_widget.update_local_settings(
+ value.get(LOCAL_GENERAL_KEY)
+ )
+ self.app_widget.update_local_settings(
+ value.get(LOCAL_APPS_KEY)
+ )
+ self.projects_widget.update_local_settings(
+ value.get(LOCAL_PROJECTS_KEY)
+ )
+
+ def settings_value(self):
+ output = {}
+ general_value = self.general_widget.settings_value()
+ if general_value:
+ output[LOCAL_GENERAL_KEY] = general_value
+
+ app_value = self.app_widget.settings_value()
+ if app_value:
+ output[LOCAL_APPS_KEY] = app_value
+
+ projects_value = self.projects_widget.settings_value()
+ if projects_value:
+ output[LOCAL_PROJECTS_KEY] = projects_value
+ return output
+
+
+class LocalSettingsWindow(QtWidgets.QWidget):
+ def __init__(self, parent=None):
+ super(LocalSettingsWindow, self).__init__(parent)
+
+ self.resize(1000, 600)
+
+ self.setWindowTitle("Pype Local settings")
+
+ stylesheet = style.load_stylesheet()
+ self.setStyleSheet(stylesheet)
+ self.setWindowIcon(QtGui.QIcon(style.app_icon_path()))
+
+ scroll_widget = QtWidgets.QScrollArea(self)
+ scroll_widget.setObjectName("GroupWidget")
+ settings_widget = LocalSettingsWidget(scroll_widget)
+
+ scroll_widget.setWidget(settings_widget)
+ scroll_widget.setWidgetResizable(True)
+
+ footer = QtWidgets.QWidget(self)
+
+ save_btn = QtWidgets.QPushButton("Save", footer)
+ reset_btn = QtWidgets.QPushButton("Reset", footer)
+
+ footer_layout = QtWidgets.QHBoxLayout(footer)
+ footer_layout.addWidget(reset_btn, 0)
+ footer_layout.addWidget(SpacerWidget(footer), 1)
+ footer_layout.addWidget(save_btn, 0)
+
+ main_layout = QtWidgets.QVBoxLayout(self)
+ main_layout.setContentsMargins(0, 0, 0, 0)
+ main_layout.addWidget(scroll_widget, 1)
+ main_layout.addWidget(footer, 0)
+
+ save_btn.clicked.connect(self._on_save_clicked)
+ reset_btn.clicked.connect(self._on_reset_clicked)
+
+ self.settings_widget = settings_widget
+ self.reset_btn = reset_btn
+ self.save_btn = save_btn
+
+ self.reset()
+
+ def reset(self):
+ value = get_local_settings()
+ self.settings_widget.update_local_settings(value)
+
+ def _on_reset_clicked(self):
+ self.reset()
+
+ def _on_save_clicked(self):
+ value = self.settings_widget.settings_value()
+ save_local_settings(value)
+ self.reset()
diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py
index 692e9a9859..4010b8ab20 100644
--- a/pype/tools/settings/settings/widgets/base.py
+++ b/pype/tools/settings/settings/widgets/base.py
@@ -1,4 +1,6 @@
from Qt import QtWidgets, QtGui, QtCore
+from .lib import CHILD_OFFSET
+from .widgets import ExpandingWidget
class BaseWidget(QtWidgets.QWidget):
@@ -161,27 +163,92 @@ class BaseWidget(QtWidgets.QWidget):
class InputWidget(BaseWidget):
+ def create_ui(self):
+ if self.entity.use_label_wrap:
+ label = None
+ self._create_label_wrap_ui()
+ else:
+ label = self.entity.label
+ self.label_widget = None
+ self.body_widget = None
+ self.content_widget = self
+ self.content_layout = self._create_layout(self)
+
+ self._add_inputs_to_layout()
+
+ self.entity_widget.add_widget_to_layout(self, label)
+
+ def _create_label_wrap_ui(self):
+ content_widget = QtWidgets.QWidget(self)
+ content_widget.setObjectName("ContentWidget")
+
+ content_widget.setProperty("content_state", "")
+ content_layout_margins = (CHILD_OFFSET, 5, 0, 0)
+
+ body_widget = ExpandingWidget(self.entity.label, self)
+ label_widget = body_widget.label_widget
+ body_widget.set_content_widget(content_widget)
+
+ content_layout = self._create_layout(content_widget)
+ content_layout.setContentsMargins(*content_layout_margins)
+
+ main_layout = QtWidgets.QHBoxLayout(self)
+ main_layout.setContentsMargins(0, 0, 0, 0)
+ main_layout.setSpacing(0)
+ main_layout.addWidget(body_widget)
+
+ self.label_widget = label_widget
+ self.body_widget = body_widget
+ self.content_widget = content_widget
+ self.content_layout = content_layout
+
+ def _create_layout(self, parent_widget):
+ layout = QtWidgets.QHBoxLayout(parent_widget)
+ layout.setContentsMargins(0, 0, 0, 0)
+ layout.setSpacing(5)
+ return layout
+
+ def _add_inputs_to_layout(self):
+ raise NotImplementedError(
+ "Method `_add_inputs_to_layout` not implemented {}".format(
+ self.__class__.__name__
+ )
+ )
+
def update_style(self):
has_unsaved_changes = self.entity.has_unsaved_changes
if not has_unsaved_changes and self.entity.group_item:
has_unsaved_changes = self.entity.group_item.has_unsaved_changes
- state = self.get_style_state(
+ style_state = self.get_style_state(
self.is_invalid,
has_unsaved_changes,
self.entity.has_project_override,
self.entity.has_studio_override
)
- if self._style_state == state:
+ if self._style_state == style_state:
return
- self._style_state = state
+ self._style_state = style_state
- self.input_field.setProperty("input-state", state)
+ self.input_field.setProperty("input-state", style_state)
self.input_field.style().polish(self.input_field)
if self.label_widget:
- self.label_widget.setProperty("state", state)
+ self.label_widget.setProperty("state", style_state)
self.label_widget.style().polish(self.label_widget)
+ if self.body_widget:
+ if style_state:
+ child_style_state = "child-{}".format(style_state)
+ else:
+ child_style_state = ""
+
+ self.body_widget.side_line_widget.setProperty(
+ "state", child_style_state
+ )
+ self.body_widget.side_line_widget.style().polish(
+ self.body_widget.side_line_widget
+ )
+
@property
def child_invalid(self):
return self.is_invalid
diff --git a/pype/tools/settings/settings/widgets/item_widgets.py b/pype/tools/settings/settings/widgets/item_widgets.py
index fd33f337d7..bdc96840f2 100644
--- a/pype/tools/settings/settings/widgets/item_widgets.py
+++ b/pype/tools/settings/settings/widgets/item_widgets.py
@@ -24,21 +24,30 @@ from .lib import CHILD_OFFSET
class DictImmutableKeysWidget(BaseWidget):
def create_ui(self):
- self._child_style_state = ""
self.input_fields = []
self.checkbox_child = None
- if not self.entity.is_dynamic_item and not self.entity.label:
- self._ui_item_without_label()
+
+ self.label_widget = None
+ self.body_widget = None
+ self.content_widget = None
+ self.content_layout = None
+
+ label = None
+ if self.entity.is_dynamic_item:
+ self._ui_as_dynamic_item()
+
+ elif self.entity.use_label_wrap:
+ self._ui_label_wrap()
+ self.checkbox_child = self.entity.non_gui_children.get(
+ self.entity.checkbox_key
+ )
else:
- self._ui_item_or_as_widget()
- if not self.entity.is_dynamic_item:
- self.checkbox_child = self.entity.non_gui_children.get(
- self.entity.checkbox_key
- )
+ self._ui_item_base()
+ label = self.entity.label
- self.widget_mapping = {}
- self.wrapper_widgets_by_id = {}
+ self._parent_widget_by_entity_id = {}
+ self._added_wrapper_ids = set()
self._prepare_entity_layouts(
self.entity.gui_layout, self.content_widget
)
@@ -50,13 +59,13 @@ class DictImmutableKeysWidget(BaseWidget):
)
)
- self.entity_widget.add_widget_to_layout(self)
+ self.entity_widget.add_widget_to_layout(self, label)
def _prepare_entity_layouts(self, children, widget):
for child in children:
if not isinstance(child, dict):
if child is not self.checkbox_child:
- self.widget_mapping[child.id] = widget
+ self._parent_widget_by_entity_id[child.id] = widget
continue
if child["type"] == "collapsible-wrap":
@@ -70,73 +79,77 @@ class DictImmutableKeysWidget(BaseWidget):
"Unknown Wrapper type \"{}\"".format(child["type"])
)
- self.widget_mapping[wrapper.id] = widget
- self.wrapper_widgets_by_id[wrapper.id] = wrapper
- self.add_widget_to_layout(wrapper)
+ self._parent_widget_by_entity_id[wrapper.id] = widget
+
self._prepare_entity_layouts(child["children"], wrapper)
- def _ui_item_without_label(self):
+ def _ui_item_base(self):
self.setObjectName("DictInvisible")
- self.body_widget = None
self.content_widget = self
self.content_layout = QtWidgets.QGridLayout(self)
self.content_layout.setContentsMargins(0, 0, 0, 0)
self.content_layout.setSpacing(5)
- def _ui_item_or_as_widget(self):
+ def _ui_as_dynamic_item(self):
content_widget = QtWidgets.QWidget(self)
+ content_widget.setObjectName("DictAsWidgetBody")
- if self.entity.is_dynamic_item:
- content_widget.setObjectName("DictAsWidgetBody")
- show_borders = str(int(self.entity.show_borders))
- content_widget.setProperty("show_borders", show_borders)
- content_layout_margins = (5, 5, 5, 5)
- main_layout_spacing = 5
- body_widget = None
- label_widget = QtWidgets.QLabel(self.entity.label)
+ show_borders = str(int(self.entity.show_borders))
+ content_widget.setProperty("show_borders", show_borders)
+ label_widget = QtWidgets.QLabel(self.entity.label)
+
+ content_layout = QtWidgets.QGridLayout(content_widget)
+ content_layout.setContentsMargins(5, 5, 5, 5)
+
+ main_layout = QtWidgets.QHBoxLayout(self)
+ main_layout.setContentsMargins(0, 0, 0, 0)
+ main_layout.setSpacing(5)
+ main_layout.addWidget(content_widget)
+
+ self.label_widget = label_widget
+ self.content_widget = content_widget
+ self.content_layout = content_layout
+
+ def _ui_label_wrap(self):
+ content_widget = QtWidgets.QWidget(self)
+ content_widget.setObjectName("ContentWidget")
+
+ if self.entity.highlight_content:
+ content_state = "hightlighted"
+ bottom_margin = 5
else:
- content_widget.setObjectName("ContentWidget")
- if self.entity.highlight_content:
- content_state = "hightlighted"
- bottom_margin = 5
- else:
- content_state = ""
- bottom_margin = 0
- content_widget.setProperty("content_state", content_state)
- content_layout_margins = (CHILD_OFFSET, 5, 0, bottom_margin)
- main_layout_spacing = 0
+ content_state = ""
+ bottom_margin = 0
+ content_widget.setProperty("content_state", content_state)
+ content_layout_margins = (CHILD_OFFSET, 5, 0, bottom_margin)
- body_widget = ExpandingWidget(self.entity.label, self)
- label_widget = body_widget.label_widget
- body_widget.set_content_widget(content_widget)
+ body_widget = ExpandingWidget(self.entity.label, self)
+ label_widget = body_widget.label_widget
+ body_widget.set_content_widget(content_widget)
content_layout = QtWidgets.QGridLayout(content_widget)
content_layout.setContentsMargins(*content_layout_margins)
main_layout = QtWidgets.QHBoxLayout(self)
main_layout.setContentsMargins(0, 0, 0, 0)
- main_layout.setSpacing(main_layout_spacing)
- if not body_widget:
- main_layout.addWidget(content_widget)
- else:
- main_layout.addWidget(body_widget)
+ main_layout.setSpacing(0)
+ main_layout.addWidget(body_widget)
self.label_widget = label_widget
self.body_widget = body_widget
self.content_widget = content_widget
self.content_layout = content_layout
- if body_widget:
- if len(self.input_fields) == 1 and self.checkbox_widget:
- body_widget.hide_toolbox(hide_content=True)
+ if len(self.input_fields) == 1 and self.checkbox_widget:
+ body_widget.hide_toolbox(hide_content=True)
- elif self.entity.collapsible:
- if not self.entity.collapsed:
- body_widget.toggle_content()
- else:
- body_widget.hide_toolbox(hide_content=False)
+ elif self.entity.collapsible:
+ if not self.entity.collapsed:
+ body_widget.toggle_content()
+ else:
+ body_widget.hide_toolbox(hide_content=False)
def add_widget_to_layout(self, widget, label=None):
if self.checkbox_child and widget.entity is self.checkbox_child:
@@ -148,9 +161,12 @@ class DictImmutableKeysWidget(BaseWidget):
else:
map_id = widget.entity.id
- wrapper = self.widget_mapping[map_id]
+ wrapper = self._parent_widget_by_entity_id[map_id]
if wrapper is not self.content_widget:
wrapper.add_widget_to_layout(widget, label)
+ if wrapper.id not in self._added_wrapper_ids:
+ self.add_widget_to_layout(wrapper)
+ self._added_wrapper_ids.add(wrapper.id)
return
row = self.content_layout.rowCount()
@@ -172,7 +188,7 @@ class DictImmutableKeysWidget(BaseWidget):
for input_field in self.input_fields:
input_field.hierarchical_style_update()
- def update_style(self, is_overriden=None):
+ def update_style(self):
if not self.body_widget and not self.label_widget:
return
@@ -186,36 +202,8 @@ class DictImmutableKeysWidget(BaseWidget):
has_project_override = self.entity.has_project_override
has_studio_override = self.entity.has_studio_override
- is_invalid = self.is_invalid
- if self.body_widget:
- child_style_state = self.get_style_state(
- is_invalid,
- has_unsaved_changes,
- has_project_override,
- has_studio_override
- )
-
- if child_style_state:
- child_style_state = "child-{}".format(child_style_state)
-
- if self._child_style_state != child_style_state:
- self.body_widget.side_line_widget.setProperty(
- "state", child_style_state
- )
- self.body_widget.side_line_widget.style().polish(
- self.body_widget.side_line_widget
- )
- self._child_style_state = child_style_state
-
- # There is nothing to care if there is no label
- if not self.label_widget:
- return
- # Don't change label if is not group or under group item
- if not self.entity.is_group and not self.entity.group_item:
- return
-
style_state = self.get_style_state(
- is_invalid,
+ self.is_invalid,
has_unsaved_changes,
has_project_override,
has_studio_override
@@ -223,11 +211,32 @@ class DictImmutableKeysWidget(BaseWidget):
if self._style_state == style_state:
return
+ self._style_state = style_state
+
+ if self.body_widget:
+ if style_state:
+ child_style_state = "child-{}".format(style_state)
+ else:
+ child_style_state = ""
+
+ self.body_widget.side_line_widget.setProperty(
+ "state", child_style_state
+ )
+ self.body_widget.side_line_widget.style().polish(
+ self.body_widget.side_line_widget
+ )
+
+ # There is nothing to care if there is no label
+ if not self.label_widget:
+ return
+
+ # Don't change label if is not group or under group item
+ if not self.entity.is_group and not self.entity.group_item:
+ return
+
self.label_widget.setProperty("state", style_state)
self.label_widget.style().polish(self.label_widget)
- self._style_state = style_state
-
def _on_entity_change(self):
pass
@@ -250,26 +259,23 @@ class DictImmutableKeysWidget(BaseWidget):
class BoolWidget(InputWidget):
- def create_ui(self):
+ def _add_inputs_to_layout(self):
checkbox_height = self.style().pixelMetric(
QtWidgets.QStyle.PM_IndicatorHeight
)
- self.input_field = NiceCheckbox(height=checkbox_height, parent=self)
+ self.input_field = NiceCheckbox(
+ height=checkbox_height, parent=self.content_widget
+ )
- spacer = QtWidgets.QWidget(self)
+ spacer = QtWidgets.QWidget(self.content_widget)
spacer.setAttribute(QtCore.Qt.WA_TranslucentBackground)
- layout = QtWidgets.QHBoxLayout(self)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setSpacing(5)
-
- layout.addWidget(self.input_field, 0)
- layout.addWidget(spacer, 1)
+ self.content_layout.addWidget(self.input_field, 0)
+ self.content_layout.addWidget(spacer, 1)
self.setFocusProxy(self.input_field)
self.input_field.stateChanged.connect(self._on_value_change)
- self.entity_widget.add_widget_to_layout(self, self.entity.label)
def _on_entity_change(self):
if self.entity.value != self.input_field.isChecked():
@@ -285,12 +291,12 @@ class BoolWidget(InputWidget):
class TextWidget(InputWidget):
- def create_ui(self):
+ def _add_inputs_to_layout(self):
multiline = self.entity.multiline
if multiline:
- self.input_field = QtWidgets.QPlainTextEdit(self)
+ self.input_field = QtWidgets.QPlainTextEdit(self.content_widget)
else:
- self.input_field = QtWidgets.QLineEdit(self)
+ self.input_field = QtWidgets.QLineEdit(self.content_widget)
placeholder_text = self.entity.placeholder_text
if placeholder_text:
@@ -302,15 +308,10 @@ class TextWidget(InputWidget):
if multiline:
layout_kwargs["alignment"] = QtCore.Qt.AlignTop
- layout = QtWidgets.QHBoxLayout(self)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setSpacing(5)
- layout.addWidget(self.input_field, 1, **layout_kwargs)
+ self.content_layout.addWidget(self.input_field, 1, **layout_kwargs)
self.input_field.textChanged.connect(self._on_value_change)
- self.entity_widget.add_widget_to_layout(self, self.entity.label)
-
def _on_entity_change(self):
if self.entity.value != self.input_value():
self.set_entity_value()
@@ -335,26 +336,20 @@ class TextWidget(InputWidget):
class NumberWidget(InputWidget):
- def create_ui(self):
- layout = QtWidgets.QHBoxLayout(self)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setSpacing(5)
-
+ def _add_inputs_to_layout(self):
kwargs = {
"minimum": self.entity.minimum,
"maximum": self.entity.maximum,
"decimal": self.entity.decimal
}
- self.input_field = NumberSpinBox(self, **kwargs)
+ self.input_field = NumberSpinBox(self.content_widget, **kwargs)
self.setFocusProxy(self.input_field)
- layout.addWidget(self.input_field, 1)
+ self.content_layout.addWidget(self.input_field, 1)
self.input_field.valueChanged.connect(self._on_value_change)
- self.entity_widget.add_widget_to_layout(self, self.entity.label)
-
def _on_entity_change(self):
if self.entity.value != self.input_field.value():
self.set_entity_value()
@@ -419,12 +414,8 @@ class RawJsonInput(QtWidgets.QPlainTextEdit):
class RawJsonWidget(InputWidget):
- def create_ui(self):
- layout = QtWidgets.QHBoxLayout(self)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setSpacing(5)
-
- self.input_field = RawJsonInput(self)
+ def _add_inputs_to_layout(self):
+ self.input_field = RawJsonInput(self.content_widget)
self.input_field.setSizePolicy(
QtWidgets.QSizePolicy.Minimum,
QtWidgets.QSizePolicy.MinimumExpanding
@@ -432,10 +423,11 @@ class RawJsonWidget(InputWidget):
self.setFocusProxy(self.input_field)
- layout.addWidget(self.input_field, 1, alignment=QtCore.Qt.AlignTop)
+ self.content_layout.addWidget(
+ self.input_field, 1, alignment=QtCore.Qt.AlignTop
+ )
self.input_field.textChanged.connect(self._on_value_change)
- self.entity_widget.add_widget_to_layout(self, self.entity.label)
def set_entity_value(self):
self.input_field.set_value(self.entity.value)
@@ -463,31 +455,24 @@ class RawJsonWidget(InputWidget):
class EnumeratorWidget(InputWidget):
- def create_ui(self):
- layout = QtWidgets.QHBoxLayout(self)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setSpacing(5)
-
+ def _add_inputs_to_layout(self):
if self.entity.multiselection:
self.input_field = MultiSelectionComboBox(
- placeholder=self.entity.placeholder, parent=self
+ placeholder=self.entity.placeholder, parent=self.content_widget
)
- model = self.input_field.model()
- for idx in range(self.input_field.count()):
- model.item(idx).setCheckable(True)
+
else:
- self.input_field = ComboBox(self)
+ self.input_field = ComboBox(self.content_widget)
for enum_item in self.entity.enum_items:
for value, label in enum_item.items():
self.input_field.addItem(label, value)
- layout.addWidget(self.input_field, 0)
+ self.content_layout.addWidget(self.input_field, 0)
self.setFocusProxy(self.input_field)
self.input_field.value_changed.connect(self._on_value_change)
- self.entity_widget.add_widget_to_layout(self, self.entity.label)
def _on_entity_change(self):
if self.entity.value != self.input_field.value():
@@ -572,12 +557,8 @@ class PathWidget(BaseWidget):
class PathInputWidget(InputWidget):
- def create_ui(self, label_widget=None):
- layout = QtWidgets.QHBoxLayout(self)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setSpacing(5)
-
- self.input_field = QtWidgets.QLineEdit(self)
+ def _add_inputs_to_layout(self):
+ self.input_field = QtWidgets.QLineEdit(self.content_widget)
self.args_input_field = None
if self.entity.with_arguments:
self.input_field.setPlaceholderText("Executable path")
@@ -585,15 +566,13 @@ class PathInputWidget(InputWidget):
self.args_input_field.setPlaceholderText("Arguments")
self.setFocusProxy(self.input_field)
- layout.addWidget(self.input_field, 8)
+ self.content_layout.addWidget(self.input_field, 8)
self.input_field.textChanged.connect(self._on_value_change)
if self.args_input_field:
- layout.addWidget(self.args_input_field, 2)
+ self.content_layout.addWidget(self.args_input_field, 2)
self.args_input_field.textChanged.connect(self._on_value_change)
- self.entity_widget.add_widget_to_layout(self, self.entity.label)
-
def _on_entity_change(self):
if self.entity.value != self.input_value():
self.set_entity_value()
diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py
index 9a99561ea8..da9cdd75cf 100644
--- a/pype/tools/settings/settings/widgets/multiselection_combobox.py
+++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py
@@ -54,11 +54,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
self.setItemDelegate(self.delegate)
self.lines = {}
- self.item_height = (
- self.fontMetrics().height()
- + (2 * self.top_bottom_padding)
- + (2 * self.top_bottom_margins)
- )
+ self.item_height = None
def mousePressEvent(self, event):
"""Reimplemented."""
@@ -157,6 +153,11 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
return super(MultiSelectionComboBox, self).eventFilter(obj, event)
+ def addItem(self, *args, **kwargs):
+ idx = self.count()
+ super(MultiSelectionComboBox, self).addItem(*args, **kwargs)
+ self.model().item(idx).setCheckable(True)
+
def paintEvent(self, event):
"""Reimplemented."""
painter = QtWidgets.QStylePainter(self)
@@ -173,6 +174,12 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
return
font_metricts = self.fontMetrics()
+
+ if self.item_height is None:
+ self.updateGeometry()
+ self.update()
+ return
+
for line, items in self.lines.items():
top_y = (
option.rect.top()
@@ -187,11 +194,13 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
label_rect.moveTop(top_y)
label_rect.moveLeft(left_x)
label_rect.setHeight(self.item_height)
+ label_rect.setWidth(
+ label_rect.width() + self.left_right_padding
+ )
bg_rect = QtCore.QRectF(label_rect)
bg_rect.setWidth(
- label_rect.width()
- + (2 * self.left_right_padding)
+ label_rect.width() + self.left_right_padding
)
left_x = bg_rect.right() + self.item_spacing
@@ -264,6 +273,13 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
lines = len(self.lines)
if lines == 0:
lines = 1
+
+ if self.item_height is None:
+ self.item_height = (
+ self.fontMetrics().height()
+ + (2 * self.top_bottom_padding)
+ + (2 * self.top_bottom_margins)
+ )
value.setHeight(
(lines * self.item_height)
+ (2 * self.top_bottom_margins)
diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py
index fd8d9d753c..656aaaa652 100644
--- a/pype/tools/settings/settings/widgets/widgets.py
+++ b/pype/tools/settings/settings/widgets/widgets.py
@@ -664,9 +664,8 @@ class ProjectListWidget(QtWidgets.QWidget):
self.current_project = None
if self.dbcon:
- for project_doc in tuple(self.dbcon.projects()):
- items.append(project_doc["name"])
-
+ for project_name in self.dbcon.database.collection_names():
+ items.append(project_name)
for item in items:
model.appendRow(QtGui.QStandardItem(item))
diff --git a/pyproject.toml b/pyproject.toml
index dc2a956cb5..0b5e8b451c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,15 +4,18 @@ version = "3.0.0"
description = "Multi-platform open-source pipeline built around the Avalon platform, expanding it with extra features and integrations."
authors = ["Pype Club "]
license = "MIT License"
+homepage = "https://pype.club"
+documentation = "https://pype.club/docs/artist_getting_started"
+repository = "https://github.com/pypeclub/pype"
+readme = "README.md"
+keywords = ["Pipeline", "Avalon", "VFX", "animation", "automation", "tracking", "asset management"]
[tool.poetry.dependencies]
python = "3.7.*"
+aiohttp = "^3.7"
aiohttp_json_rpc = "*" # TVPaint server
acre = { git = "https://github.com/pypeclub/acre.git" }
-opentimelineio = [
- { git = "https://github.com/pypeclub/OpenTimelineIO.git", branch="develop", markers = "sys_platform == 'win32'" },
- { git = "https://github.com/PixarAnimationStudios/OpenTimelineIO.git", markers = "sys_platform == 'darwin'" }
-]
+opentimelineio = { version = "0.14.0.dev1", source = "pype" }
appdirs = "^1.4.3"
blessed = "^1.17" # pype terminal formatting
clique = "1.5.*"
@@ -33,13 +36,17 @@ speedcopy = "^2.1"
six = "^1.15"
wsrpc_aiohttp = "^3.1.1" # websocket server
pywin32 = { version = "300", markers = "sys_platform == 'win32'" }
-jinxed = { version = "^1.0.1", markers = "sys_platform == 'darwin'" }
+jinxed = [
+ { version = "^1.0.1", markers = "sys_platform == 'darwin'" },
+ { version = "^1.0.1", markers = "sys_platform == 'linux'" }
+]
+python3-xlib = { version="*", markers = "sys_platform == 'linux'"}
[tool.poetry.dev-dependencies]
flake8 = "^3.7"
autopep8 = "^1.4"
coverage = "*"
-cx_freeze = "^6.1"
+cx_freeze = "^6.5"
jedi = "^0.13"
Jinja2 = "^2.11"
pycodestyle = "^2.5.0"
@@ -56,6 +63,14 @@ recommonmark = "*"
tqdm = "*"
wheel = "*"
+[tool.poetry.urls]
+"Bug Tracker" = "https://github.com/pypeclub/pype/issues"
+"Discussions" = "https://github.com/pypeclub/pype/discussions"
+
+[[tool.poetry.source]]
+name = "pype"
+url = "https://d.r1.wbsprt.com/pype.club/distribute/"
+
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
diff --git a/repos/avalon-core b/repos/avalon-core
index 93c4a89b3e..eae14f2960 160000
--- a/repos/avalon-core
+++ b/repos/avalon-core
@@ -1 +1 @@
-Subproject commit 93c4a89b3e98ae88030e62bb9ad6c07220b23234
+Subproject commit eae14f2960c4ccf2f0211e0726e88563129c0296
diff --git a/tools/build.sh b/tools/build.sh
index 0b97e8d8df..27d10f1d4d 100755
--- a/tools/build.sh
+++ b/tools/build.sh
@@ -62,7 +62,7 @@ BIWhite='\033[1;97m' # White
# None
###############################################################################
detect_python () {
- echo -e "${BIGreen}>>>${RST} Using Python \c"
+ echo -e "${BIGreen}>>>${RST} Using python \c"
local version_command
version_command="import sys;print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))"
local python_version
@@ -72,9 +72,13 @@ detect_python () {
set -- $python_version
IFS="$oIFS"
if [ "$1" -ge "3" ] && [ "$2" -ge "6" ] ; then
- echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}"
+ if [ "$2" -gt "7" ] ; then
+ echo -e "${BIWhite}[${RST} ${BIRed}$1.$2 ${BIWhite}]${RST} - ${BIRed}FAILED${RST} ${BIYellow}Version is new and unsupported, use${RST} ${BIPurple}3.7.x${RST}"; return 1;
+ else
+ echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}"
+ fi
else
- command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}FAILED${RST} ${BIYellow} Version [${RST}${BICyan}$1.$2${RST}]${BIYellow} is old and unsupported${RST}"; return 1; }
+ command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}$1.$2$ - ${BIRed}FAILED${RST} ${BIYellow}Version is old and unsupported${RST}"; return 1; }
fi
}
@@ -88,7 +92,8 @@ detect_python () {
# None
###############################################################################
clean_pyc () {
- path=${1:-$pype_root}
+ local path
+ path=$pype_root
echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c"
find "$path" -regex '^.*\(__pycache__\|\.py[co]\)$' -delete
echo -e "${BIGreen}DONE${RST}"
@@ -107,28 +112,58 @@ realpath () {
echo $(cd $(dirname "$1") || return; pwd)/$(basename "$1")
}
+##############################################################################
+# Install Poetry when needed
+# Globals:
+# PATH
+# Arguments:
+# None
+# Returns:
+# None
+###############################################################################
+install_poetry () {
+ echo -e "${BIGreen}>>>${RST} Installing Poetry ..."
+ command -v curl >/dev/null 2>&1 || { echo -e "${BIRed}!!!${RST}${BIYellow} Missing ${RST}${BIBlue}curl${BIYellow} command.${RST}"; return 1; }
+ curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3 -
+ export PATH="$PATH:$HOME/.poetry/bin"
+}
+
# Main
-echo -e "${BGreen}"
-art
-echo -e "${RST}"
-detect_python || return 1
+main () {
+ echo -e "${BGreen}"
+ art
+ echo -e "${RST}"
+ detect_python || return 1
-# Directories
-pype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}")))
-pushd "$pype_root" || return > /dev/null
+ # Directories
+ pype_root=$(dirname $(dirname "$(realpath ${BASH_SOURCE[0]})"))
+ pushd "$pype_root" > /dev/null || return > /dev/null
-version_command="import os;exec(open(os.path.join('$pype_root', 'pype', 'version.py')).read());print(__version__);"
-pype_version="$(python3 <<< ${version_command})"
+ version_command="import os;exec(open(os.path.join('$pype_root', 'pype', 'version.py')).read());print(__version__);"
+ pype_version="$(python3 <<< ${version_command})"
-echo -e "${BIYellow}---${RST} Cleaning build directory ..."
-rm -rf "$pype_root/build" && mkdir "$pype_root/build" > /dev/null
+ echo -e "${BIYellow}---${RST} Cleaning build directory ..."
+ rm -rf "$pype_root/build" && mkdir "$pype_root/build" > /dev/null
-echo -e "${BIGreen}>>>${RST} Building Pype ${BIWhite}[${RST} ${BIGreen}$pype_version${RST} ${BIWhite}]${RST}"
-echo -e "${BIGreen}>>>${RST} Cleaning cache files ..."
-clean_pyc
-echo -e "${BIGreen}>>>${RST} Building ..."
-poetry run python "$pype_root/setup.py" build > "$pype_root/build/build.log"
-poetry run python "$pype_root/tools/build_dependencies.py"
+ echo -e "${BIGreen}>>>${RST} Building Pype ${BIWhite}[${RST} ${BIGreen}$pype_version${RST} ${BIWhite}]${RST}"
+ echo -e "${BIGreen}>>>${RST} Cleaning cache files ..."
+ clean_pyc
-echo -e "${BICyan}>>>${RST} All done. You will find Pype and build log in \c"
-echo -e "${BIWhite}$pype_root/build${RST} directory."
+ echo -e "${BIGreen}>>>${RST} Reading Poetry ... \c"
+ if [ -f "$HOME/.poetry/bin/poetry" ]; then
+ echo -e "${BIGreen}OK${RST}"
+ export PATH="$PATH:$HOME/.poetry/bin"
+ else
+ echo -e "${BIYellow}NOT FOUND${RST}"
+ install_poetry || { echo -e "${BIRed}!!!${RST} Poetry installation failed"; return; }
+ fi
+
+ echo -e "${BIGreen}>>>${RST} Building ..."
+ poetry run python3 "$pype_root/setup.py" build > "$pype_root/build/build.log" || { echo -e "${BIRed}!!!${RST} Build failed, see the build log."; return; }
+ poetry run python3 "$pype_root/tools/build_dependencies.py"
+
+ echo -e "${BICyan}>>>${RST} All done. You will find Pype and build log in \c"
+ echo -e "${BIWhite}$pype_root/build${RST} directory."
+}
+
+main
diff --git a/tools/create_env.ps1 b/tools/create_env.ps1
index 1c5e6e35e6..1ea983cdd2 100644
--- a/tools/create_env.ps1
+++ b/tools/create_env.ps1
@@ -13,6 +13,12 @@ PS> .\create_env.ps1
#>
+$arguments=$ARGS
+$poetry_verbosity=""
+if($arguments -eq "--verbose") {
+ $poetry_verbosity="-vvv"
+}
+
function Exit-WithCode($exitcode) {
# Only exit this host process if it's a child of another PowerShell parent process...
$parentPID = (Get-CimInstance -ClassName Win32_Process -Filter "ProcessId=$PID" | Select-Object -Property ParentProcessId).ParentProcessId
@@ -43,8 +49,40 @@ function Install-Poetry() {
}
-$current_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
-$pype_root = (Get-Item $current_dir).parent.FullName
+function Test-Python() {
+ Write-Host ">>> " -NoNewline -ForegroundColor green
+ Write-Host "Detecting host Python ... " -NoNewline
+ if (-not (Get-Command "python" -ErrorAction SilentlyContinue)) {
+ Write-Host "!!! Python not detected" -ForegroundColor red
+ Set-Location -Path $current_dir
+ Exit-WithCode 1
+ }
+ $version_command = @'
+import sys
+print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))
+'@
+
+ $p = & python -c $version_command
+ $env:PYTHON_VERSION = $p
+ $m = $p -match '(\d+)\.(\d+)'
+ if(-not $m) {
+ Write-Host "!!! Cannot determine version" -ForegroundColor red
+ Set-Location -Path $current_dir
+ Exit-WithCode 1
+ }
+ # We are supporting python 3.6 and up
+ if(($matches[1] -lt 3) -or ($matches[2] -lt 7)) {
+ Write-Host "FAILED Version [ $p ] is old and unsupported" -ForegroundColor red
+ Set-Location -Path $current_dir
+ Exit-WithCode 1
+ }
+ Write-Host "OK [ $p ]" -ForegroundColor green
+}
+
+
+$current_dir = Get-Location
+$script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
+$pype_root = (Get-Item $script_dir).parent.FullName
Set-Location -Path $pype_root
@@ -72,33 +110,14 @@ $pype_version = $result[0].Groups['version'].Value
if (-not $pype_version) {
Write-Host "!!! " -ForegroundColor yellow -NoNewline
Write-Host "Cannot determine Pype version."
+ Set-Location -Path $current_dir
Exit-WithCode 1
}
+Write-Host ">>> " -NoNewline -ForegroundColor Green
+Write-Host "Found Pype version " -NoNewline
+Write-Host "[ $($pype_version) ]" -ForegroundColor Green
-Write-Host ">>> " -NoNewline -ForegroundColor green
-Write-Host "Detecting host Python ... " -NoNewline
-if (-not (Get-Command "python" -ErrorAction SilentlyContinue)) {
- Write-Host "!!! Python not detected" -ForegroundColor red
- Exit-WithCode 1
-}
-$version_command = @'
-import sys
-print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))
-'@
-
-$p = & python -c $version_command
-$env:PYTHON_VERSION = $p
-$m = $p -match '(\d+)\.(\d+)'
-if(-not $m) {
- Write-Host "!!! Cannot determine version" -ForegroundColor red
- Exit-WithCode 1
-}
-# We are supporting python 3.6 and up
-if(($matches[1] -lt 3) -or ($matches[2] -lt 7)) {
- Write-Host "FAILED Version [ $p ] is old and unsupported" -ForegroundColor red
- Exit-WithCode 1
-}
-Write-Host "OK [ $p ]" -ForegroundColor green
+Test-Python
Write-Host ">>> " -NoNewline -ForegroundColor Green
Write-Host "Reading Poetry ... " -NoNewline
@@ -112,12 +131,17 @@ if (-not (Test-Path -PathType Container -Path "$($env:USERPROFILE)\.poetry\bin")
if (-not (Test-Path -PathType Leaf -Path "$($pype_root)\poetry.lock")) {
Write-Host ">>> " -NoNewline -ForegroundColor green
- Write-Host "Creating virtual environment."
- & poetry install
+ Write-Host "Installing virtual environment and creating lock."
} else {
Write-Host ">>> " -NoNewline -ForegroundColor green
- Write-Host "Updating virtual environment."
- & poetry update
+ Write-Host "Installing virtual environment from lock."
+}
+& poetry install $poetry_verbosity
+if ($LASTEXITCODE -ne 0) {
+ Write-Host "!!! " -ForegroundColor yellow -NoNewline
+ Write-Host "Poetry command failed."
+ Set-Location -Path $current_dir
+ Exit-WithCode 1
}
Set-Location -Path $current_dir
Write-Host ">>> " -NoNewline -ForegroundColor green
diff --git a/tools/create_env.sh b/tools/create_env.sh
index 5e9f21abcc..52bc79ca83 100755
--- a/tools/create_env.sh
+++ b/tools/create_env.sh
@@ -52,6 +52,24 @@ BIPurple='\033[1;95m' # Purple
BICyan='\033[1;96m' # Cyan
BIWhite='\033[1;97m' # White
+
+poetry_verbosity=""
+while :; do
+ case $1 in
+ --verbose)
+ poetry_verbosity="-vvv"
+ ;;
+ --)
+ shift
+ break
+ ;;
+ *)
+ break
+ esac
+ shift
+done
+
+
##############################################################################
# Detect required version of python
# Globals:
@@ -71,16 +89,20 @@ detect_python () {
set -- $python_version
IFS="$oIFS"
if [ "$1" -ge "3" ] && [ "$2" -ge "6" ] ; then
- echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}"
- PYTHON="python3"
+ if [ "$2" -gt "7" ] ; then
+ echo -e "${BIWhite}[${RST} ${BIRed}$1.$2 ${BIWhite}]${RST} - ${BIRed}FAILED${RST} ${BIYellow}Version is new and unsupported, use${RST} ${BIPurple}3.7.x${RST}"; return 1;
+ else
+ echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}"
+ fi
else
- command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}FAILED${RST} ${BIYellow} Version [${RST}${BICyan}$1.$2${RST}]${BIYellow} is old and unsupported${RST}"; return 1; }
+ command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}$1.$2$ - ${BIRed}FAILED${RST} ${BIYellow}Version is old and unsupported${RST}"; return 1; }
fi
}
install_poetry () {
echo -e "${BIGreen}>>>${RST} Installing Poetry ..."
- curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -
+ command -v curl >/dev/null 2>&1 || { echo -e "${BIRed}!!!${RST}${BIYellow} Missing ${RST}${BIBlue}curl${BIYellow} command.${RST}"; return 1; }
+ curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3 -
export PATH="$PATH:$HOME/.poetry/bin"
}
@@ -94,8 +116,9 @@ install_poetry () {
# None
###############################################################################
clean_pyc () {
- path=${1:-$pype_root}
- echo -e "${IGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c"
+ local path
+ path=$pype_root
+ echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c"
find "$path" -regex '^.*\(__pycache__\|\.py[co]\)$' -delete
echo -e "${BIGreen}DONE${RST}"
}
@@ -113,32 +136,44 @@ realpath () {
echo $(cd $(dirname "$1"); pwd)/$(basename "$1")
}
-# Main
-echo -e "${BGreen}"
-art
-echo -e "${RST}"
-detect_python || return 1
+main () {
+ # Main
+ echo -e "${BGreen}"
+ art
+ echo -e "${RST}"
+ detect_python || return 1
-# Directories
-pype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}")))
-pushd "$pype_root" || return > /dev/null
+ # Directories
+ pype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}")))
+ pushd "$pype_root" > /dev/null || return > /dev/null
-echo -e "${BIGreen}>>>${RST} Reading Poetry ... \c"
-if [ -f "$HOME/.poetry/bin/poetry" ]; then
- echo -e "${BIGreen}OK${RST}"
-else
- echo -e "${BIYellow}NOT FOUND${RST}"
- install_poetry
-fi
+ echo -e "${BIGreen}>>>${RST} Reading Poetry ... \c"
+ if [ -f "$HOME/.poetry/bin/poetry" ]; then
+ echo -e "${BIGreen}OK${RST}"
+ export PATH="$PATH:$HOME/.poetry/bin"
+ else
+ echo -e "${BIYellow}NOT FOUND${RST}"
+ install_poetry || { echo -e "${BIRed}!!!${RST} Poetry installation failed"; return; }
+ fi
-if [ -f "$pype_root/poetry.lock" ]; then
- echo -e "${BIGreen}>>>${RST} Updating dependencies ..."
- poetry update
-else
- echo -e "${BIGreen}>>>${RST} Installing dependencies ..."
- poetry install
-fi
+ if [ -f "$pype_root/poetry.lock" ]; then
+ echo -e "${BIGreen}>>>${RST} Updating dependencies ..."
+ else
+ echo -e "${BIGreen}>>>${RST} Installing dependencies ..."
+ fi
-echo -e "${BIGreen}>>>${RST} Cleaning cache files ..."
-clean_pyc
+ poetry install $poetry_verbosity || { echo -e "${BIRed}!!!${RST} Poetry environment installation failed"; return; }
+ echo -e "${BIGreen}>>>${RST} Cleaning cache files ..."
+ clean_pyc
+
+ # reinstall these because of bug in poetry? or cx_freeze?
+ # cx_freeze will crash on missing __pychache__ on these but
+ # reinstalling them solves the problem.
+ echo -e "${BIGreen}>>>${RST} Fixing pycache bug ..."
+ poetry run python -m pip install --upgrade pip
+ poetry run pip install --force-reinstall setuptools
+ poetry run pip install --force-reinstall wheel
+}
+
+main -3
diff --git a/tools/create_zip.ps1 b/tools/create_zip.ps1
index ee8da5acec..1780b0bb9a 100644
--- a/tools/create_zip.ps1
+++ b/tools/create_zip.ps1
@@ -33,8 +33,9 @@ function Show-PSWarning() {
}
}
-$current_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
-$pype_root = (Get-Item $current_dir).parent.FullName
+$current_dir = Get-Location
+$script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
+$pype_root = (Get-Item $script_dir).parent.FullName
Set-Location -Path $pype_root
$art = @"
diff --git a/tools/create_zip.sh b/tools/create_zip.sh
index a44d9d4be9..839b1c4827 100755
--- a/tools/create_zip.sh
+++ b/tools/create_zip.sh
@@ -70,10 +70,13 @@ detect_python () {
set -- $python_version
IFS="$oIFS"
if [ "$1" -ge "3" ] && [ "$2" -ge "6" ] ; then
- echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}"
- PYTHON="python3"
+ if [ "$2" -gt "7" ] ; then
+ echo -e "${BIWhite}[${RST} ${BIRed}$1.$2 ${BIWhite}]${RST} - ${BIRed}FAILED${RST} ${BIYellow}Version is new and unsupported, use${RST} ${BIPurple}3.7.x${RST}"; return 1;
+ else
+ echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}"
+ fi
else
- command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}FAILED${RST} ${BIYellow} Version [${RST}${BICyan}$1.$2${RST}]${BIYellow} is old and unsupported${RST}"; return 1; }
+ command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}$1.$2$ - ${BIRed}FAILED${RST} ${BIYellow}Version is old and unsupported${RST}"; return 1; }
fi
}
@@ -87,8 +90,9 @@ detect_python () {
# None
###############################################################################
clean_pyc () {
- path=${1:-$pype_root}
- echo -e "${IGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c"
+ local path
+ path=$pype_root
+ echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c"
find "$path" -regex '^.*\(__pycache__\|\.py[co]\)$' -delete
echo -e "${BIGreen}DONE${RST}"
}
@@ -107,14 +111,18 @@ realpath () {
}
# Main
-echo -e "${BGreen}"
-art
-echo -e "${RST}"
-detect_python || return 1
+main () {
+ echo -e "${BGreen}"
+ art
+ echo -e "${RST}"
+ detect_python || return 1
-# Directories
-pype_root=$(dirname $(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))))
-pushd "$pype_root" || return > /dev/null
+ # Directories
+ pype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}")))
+ pushd "$pype_root" > /dev/null || return > /dev/null
-echo -e "${BIGreen}>>>${RST} Generating zip from current sources ..."
-poetry run python "$pype_root/start.py" generate-zip "$@"
+ echo -e "${BIGreen}>>>${RST} Generating zip from current sources ..."
+ poetry run python3 "$pype_root/start.py" generate-zip "$@"
+}
+
+main "$@"
diff --git a/tools/make_docs.sh b/tools/make_docs.sh
index 68582ff5ae..ed5c72b055 100755
--- a/tools/make_docs.sh
+++ b/tools/make_docs.sh
@@ -65,17 +65,21 @@ realpath () {
}
# Main
-echo -e "${BGreen}"
-art
-echo -e "${RST}"
+main () {
+ echo -e "${BGreen}"
+ art
+ echo -e "${RST}"
-# Directories
-pype_root=$(dirname $(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))))
-pushd "$pype_root" || return > /dev/null
+ # Directories
+ pype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}")))
+ pushd "$pype_root" > /dev/null || return > /dev/null
-echo -e "${BIGreen}>>>${RST} Running apidoc ..."
-poetry run sphinx-apidoc -M -e -d 10 --ext-intersphinx --ext-todo --ext-coverage --ext-viewcode -o "$pype_root/docs/source" igniter
-poetry run sphinx-apidoc -M -e -d 10 --ext-intersphinx --ext-todo --ext-coverage --ext-viewcode -o "$pype_root/docs/source" pype vendor, pype\vendor
+ echo -e "${BIGreen}>>>${RST} Running apidoc ..."
+ poetry run sphinx-apidoc -M -e -d 10 --ext-intersphinx --ext-todo --ext-coverage --ext-viewcode -o "$pype_root/docs/source" igniter
+ poetry run sphinx-apidoc -M -e -d 10 --ext-intersphinx --ext-todo --ext-coverage --ext-viewcode -o "$pype_root/docs/source" pype vendor, pype\vendor
-echo -e "${BIGreen}>>>${RST} Building html ..."
-poetry run python "$pype_root/setup.py" build_sphinx
+ echo -e "${BIGreen}>>>${RST} Building html ..."
+ poetry run python3 "$pype_root/setup.py" build_sphinx
+}
+
+main
diff --git a/tools/run_mongo.ps1 b/tools/run_mongo.ps1
index 1b6d95ca57..a72c8b1210 100644
--- a/tools/run_mongo.ps1
+++ b/tools/run_mongo.ps1
@@ -44,18 +44,20 @@ function Find-Mongo {
# we have mongo server installed on standard Windows location
# so we can inject it to the PATH. We'll use latest version available.
$mongoVersions = Get-ChildItem -Directory 'C:\Program Files\MongoDB\Server' | Sort-Object -Property {$_.Name -as [int]}
- if(Test-Path "C:\Program Files\MongoDB\Server\$($mongoVersions[-1])\bin\mongod.exe" -PathType Leaf) {
- $env:PATH="$($env:PATH);C:\Program Files\MongoDB\Server\$($mongoVersions[-1])\bin\"
+ if(Test-Path "$($mongoVersions[-1])\bin\mongod.exe" -PathType Leaf) {
+ $env:PATH="$($env:PATH);$($mongoVersions[-1])\bin\"
Write-Host "OK" -ForegroundColor Green
Write-Host " - auto-added from [ " -NoNewline
- Write-Host "C:\Program Files\MongoDB\Server\$($mongoVersions[-1])\bin\" -NoNewLine -ForegroundColor Cyan
+ Write-Host "$($mongoVersions[-1])\bin\" -NoNewLine -ForegroundColor Cyan
Write-Host " ]"
} else {
Write-Host "FAILED " -NoNewLine -ForegroundColor Red
Write-Host "MongoDB not detected" -ForegroundColor Yellow
- Write-Host "Tried to find it on standard location [ " -NoNewline -ForegroundColor Gray
- Write-Host "C:\Program Files\MongoDB\Server\$($mongoVersions[-1])\bin\" -NoNewline -ForegroundColor White
- Write-Host " ] but failed." -ForegroundColor Gray
+ Write-Host "Tried to find it on standard location " -NoNewline -ForegroundColor Gray
+ Write-Host " [ " -NoNewline -ForegroundColor Cyan
+ Write-Host "$($mongoVersions[-1])\bin\" -NoNewline -ForegroundColor White
+ Write-Host " ] " -NonNewLine -ForegroundColor Cyan
+ Write-Host "but failed." -ForegroundColor Gray
Exit-WithCode 1
}
} else {
diff --git a/tools/run_mongo.sh b/tools/run_mongo.sh
index 6f9e0f5411..209e80ac5b 100755
--- a/tools/run_mongo.sh
+++ b/tools/run_mongo.sh
@@ -66,18 +66,20 @@ realpath () {
}
# Main
-echo -e "${BGreen}"
-art
-echo -e "${RST}"
+main () {
+ echo -e "${BGreen}"
+ art
+ echo -e "${RST}"
-# Directories
-pype_root=$(dirname $(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))))
-pushd "$pype_root" > /dev/null
+ # Directories
+ pype_root=$(dirname $(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))))
+ pushd "$pype_root" > /dev/null || return > /dev/null
-mongo_port=2707
-echo $pype_root
-dbpath="$(dirname $pype_root)/mongo_db_data"
+ mongo_port=2707
+ dbpath="$(dirname $pype_root)/mongo_db_data"
+
+ echo -e "${BIGreen}>>>${RST} Running mongodb ..."
+ mongod --dbpath "$dbpath" --port $mongo_port
+ echo -e "${BIGreen}>>>${RST} Detached to background."
+}
-echo -e "${BIGreen}>>>${RST} Running mongodb ..."
-mongod --dbpath "$dbpath" --port $mongo_port
-echo -e "${BIGreen}>>>${RST} Detached to background."
diff --git a/tools/run_settings.ps1 b/tools/run_settings.ps1
index 48ea9befdf..acecae0bb6 100644
--- a/tools/run_settings.ps1
+++ b/tools/run_settings.ps1
@@ -11,6 +11,7 @@ PS> .\run_settings.ps1
#>
+$current_dir = Get-Location
$script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
$pype_root = (Get-Item $script_dir).parent.FullName
Set-Location -Path $pype_root
diff --git a/tools/run_settings.sh b/tools/run_settings.sh
index dbf1c5ba30..99148456c0 100755
--- a/tools/run_settings.sh
+++ b/tools/run_settings.sh
@@ -70,10 +70,13 @@ detect_python () {
set -- $python_version
IFS="$oIFS"
if [ "$1" -ge "3" ] && [ "$2" -ge "6" ] ; then
- echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}"
- PYTHON="python3"
+ if [ "$2" -gt "7" ] ; then
+ echo -e "${BIWhite}[${RST} ${BIRed}$1.$2 ${BIWhite}]${RST} - ${BIRed}FAILED${RST} ${BIYellow}Version is new and unsupported, use${RST} ${BIPurple}3.7.x${RST}"; return 1;
+ else
+ echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}"
+ fi
else
- command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}FAILED${RST} ${BIYellow} Version [${RST}${BICyan}$1.$2${RST}]${BIYellow} is old and unsupported${RST}"; return 1; }
+ command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}$1.$2$ - ${BIRed}FAILED${RST} ${BIYellow}Version is old and unsupported${RST}"; return 1; }
fi
}
@@ -87,8 +90,9 @@ detect_python () {
# None
###############################################################################
clean_pyc () {
- path=${1:-$pype_root}
- echo -e "${IGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c"
+ local path
+ path=$pype_root
+ echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c"
find "$path" -regex '^.*\(__pycache__\|\.py[co]\)$' -delete
echo -e "${BIGreen}DONE${RST}"
}
@@ -107,15 +111,18 @@ realpath () {
}
# Main
-echo -e "${BGreen}"
-art
-echo -e "${RST}"
-detect_python || return 1
+main () {
+ echo -e "${BGreen}"
+ art
+ echo -e "${RST}"
+ detect_python || return 1
-# Directories
-pype_root=$(dirname $(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))))
-pushd "$pype_root" || return> /dev/null
+ # Directories
+ pype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}")))
+ pushd "$pype_root" > /dev/null || return > /dev/null
-echo -e "${BIGreen}>>>${RST} Generating zip from current sources ..."
-poetry run python "$pype_root/start.py" settings --dev
+ echo -e "${BIGreen}>>>${RST} Generating zip from current sources ..."
+ poetry run python3 "$pype_root/start.py" settings --dev
+}
+main
diff --git a/tools/run_tests.sh b/tools/run_tests.sh
index 7e68e0b0ab..df001dce97 100755
--- a/tools/run_tests.sh
+++ b/tools/run_tests.sh
@@ -71,7 +71,6 @@ detect_python () {
IFS="$oIFS"
if [ "$1" -ge "3" ] && [ "$2" -ge "6" ] ; then
echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}"
- PYTHON="python3"
else
command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}FAILED${RST} ${BIYellow} Version [${RST}${BICyan}$1.$2${RST}]${BIYellow} is old and unsupported${RST}"; return 1; }
fi
@@ -87,8 +86,9 @@ detect_python () {
# None
###############################################################################
clean_pyc () {
- path=${1:-$pype_root}
- echo -e "${IGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c"
+ local path
+ path=$pype_root
+ echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c"
find "$path" -regex '^.*\(__pycache__\|\.py[co]\)$' -delete
echo -e "${BIGreen}DONE${RST}"
}
@@ -107,19 +107,22 @@ realpath () {
}
# Main
-echo -e "${BGreen}"
-art
-echo -e "${RST}"
-detect_python || return 1
+main () {
+ echo -e "${BGreen}"
+ art
+ echo -e "${RST}"
+ detect_python || return 1
-# Directories
-pype_root=$(dirname $(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))))
-pushd "$pype_root" || return > /dev/null
+ # Directories
+ pype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}")))
+ pushd "$pype_root" || return > /dev/null
+
+ echo -e "${BIGreen}>>>${RST} Testing Pype ..."
+ original_pythonpath=$PYTHONPATH
+ export PYTHONPATH="$pype_root:$PYTHONPATH"
+ poetry run pytest -x --capture=sys --print -W ignore::DeprecationWarning "$pype_root/tests"
+ PYTHONPATH=$original_pythonpath
+}
-echo -e "${BIGreen}>>>${RST} Testing Pype ..."
-original_pythonpath=$PYTHONPATH
-export PYTHONPATH="$pype_root:$PYTHONPATH"
-poetry run pytest -x --capture=sys --print -W ignore::DeprecationWarning "$pype_root/tests"
-PYTHONPATH=$original_pythonpath
diff --git a/tools/run_tray.ps1 b/tools/run_tray.ps1
index 2c7a665fcf..9584c05925 100644
--- a/tools/run_tray.ps1
+++ b/tools/run_tray.ps1
@@ -10,6 +10,7 @@
PS> .\run_tray.ps1
#>
+$current_dir = Get-Location
$script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
$pype_root = (Get-Item $script_dir).parent.FullName
Set-Location -Path $pype_root
diff --git a/tools/run_tray.sh b/tools/run_tray.sh
index d7d3b979dc..3c63d0babe 100755
--- a/tools/run_tray.sh
+++ b/tools/run_tray.sh
@@ -70,10 +70,14 @@ detect_python () {
set -- $python_version
IFS="$oIFS"
if [ "$1" -ge "3" ] && [ "$2" -ge "6" ] ; then
- echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}"
+ if [ "$2" -gt "7" ] ; then
+ echo -e "${BIWhite}[${RST} ${BIRed}$1.$2 ${BIWhite}]${RST} - ${BIRed}FAILED${RST} ${BIYellow}Version is new and unsupported, use${RST} ${BIPurple}3.7.x${RST}"; return 1;
+ else
+ echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}"
+ fi
PYTHON="python3"
else
- command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}FAILED${RST} ${BIYellow} Version [${RST}${BICyan}$1.$2${RST}]${BIYellow} is old and unsupported${RST}"; return 1; }
+ command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}$1.$2$ - ${BIRed}FAILED${RST} ${BIYellow}Version is old and unsupported${RST}"; return 1; }
fi
}
@@ -87,8 +91,9 @@ detect_python () {
# None
###############################################################################
clean_pyc () {
- path=${1:-$pype_root}
- echo -e "${IGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c"
+ local path
+ path=$pype_root
+ echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c"
find "$path" -regex '^.*\(__pycache__\|\.py[co]\)$' -delete
echo -e "${BIGreen}DONE${RST}"
}
@@ -107,14 +112,18 @@ realpath () {
}
# Main
-echo -e "${BGreen}"
-art
-echo -e "${RST}"
-detect_python || return 1
+main () {
+ echo -e "${BGreen}"
+ art
+ echo -e "${RST}"
+ detect_python || return 1
-# Directories
-pype_root=$(dirname $(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))))
-pushd "$pype_root" || return > /dev/null
+ # Directories
+ pype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}")))
+ pushd "$pype_root" > /dev/null || return > /dev/null
-echo -e "${BIGreen}>>>${RST} Running Pype Tray with debug option ..."
-poetry run python "$pype_root/start.py" tray --debug
+ echo -e "${BIGreen}>>>${RST} Running Pype Tray with debug option ..."
+ poetry run python3 "$pype_root/start.py" tray --debug
+}
+
+main
\ No newline at end of file
diff --git a/tools/update_submodules.ps1 b/tools/update_submodules.ps1
index 22792ff6da..ca29c7ecc4 100644
--- a/tools/update_submodules.ps1
+++ b/tools/update_submodules.ps1
@@ -35,8 +35,9 @@ function Exit-WithCode($exitcode) {
exit $exitcode
}
-$current_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
-$pype_root = (Get-Item $current_dir).parent.FullName
+$current_dir = Get-Location
+$script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
+$pype_root = (Get-Item $script_dir).parent.FullName
Set-Location -Path $pype_root
diff --git a/tools/update_submodules.sh b/tools/update_submodules.sh
index c0b98f2c5e..35d943dea5 100644
--- a/tools/update_submodules.sh
+++ b/tools/update_submodules.sh
@@ -51,61 +51,6 @@ BICyan='\033[1;96m' # Cyan
BIWhite='\033[1;97m' # White
-##############################################################################
-# Detect required version of python
-# Globals:
-# colors
-# PYTHON
-# Arguments:
-# None
-# Returns:
-# None
-###############################################################################
-detect_python () {
- echo -e "${BIGreen}>>>${RST} Using python \c"
- local version_command="import sys;print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))"
- local python_version="$(python3 <<< ${version_command})"
- oIFS="$IFS"
- IFS=.
- set -- $python_version
- IFS="$oIFS"
- if [ "$1" -ge "3" ] && [ "$2" -ge "6" ] ; then
- echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}"
- PYTHON="python3"
- else
- command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}FAILED${RST} ${BIYellow} Version [${RST}${BICyan}$1.$2${RST}]${BIYellow} is old and unsupported${RST}"; return 1; }
- fi
-}
-
-##############################################################################
-# Clean pyc files in specified directory
-# Globals:
-# None
-# Arguments:
-# Optional path to clean
-# Returns:
-# None
-###############################################################################
-clean_pyc () {
- path=${1:-$pype_root}
- echo -e "${IGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c"
- find "$path" -regex '^.*\(__pycache__\|\.py[co]\)$' -delete
- echo -e "${BIGreen}DONE${RST}"
-}
-
-##############################################################################
-# Return absolute path
-# Globals:
-# None
-# Arguments:
-# Path to resolve
-# Returns:
-# None
-###############################################################################
-realpath () {
- echo $(cd $(dirname "$1"); pwd)/$(basename "$1")
-}
-
# Main
echo -e "${BGreen}"
art