diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index e9b68a54f1..039b42bff3 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -35,6 +35,12 @@ body: label: Version description: What version are you running? Look to OpenPype Tray options: + - 3.18.6-nightly.1 + - 3.18.5 + - 3.18.5-nightly.3 + - 3.18.5-nightly.2 + - 3.18.5-nightly.1 + - 3.18.4 - 3.18.4-nightly.1 - 3.18.3 - 3.18.3-nightly.2 @@ -129,12 +135,6 @@ body: - 3.15.8 - 3.15.8-nightly.3 - 3.15.8-nightly.2 - - 3.15.8-nightly.1 - - 3.15.7 - - 3.15.7-nightly.3 - - 3.15.7-nightly.2 - - 3.15.7-nightly.1 - - 3.15.6 validations: required: true - type: dropdown diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b51fade6f..14f0bc469f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,366 @@ # Changelog +## [3.18.5](https://github.com/ynput/OpenPype/tree/3.18.5) + + +[Full Changelog](https://github.com/ynput/OpenPype/compare/3.18.4...3.18.5) + +### **🚀 Enhancements** + + +
+Chore: Add addons dir only if exists #6140 + +Do not add addons directory path for addons discovery if does not exists. + + +___ + +
+ + +
+Hiero: Effect Categories - OP-7397 #6143 + +This PR introduces `Effect Categories` for the Hiero settings. This allows studios to split effect stacks into meaningful subsets. + + +___ + +
+ + +
+Nuke: Render Workfile Attributes #6146 + +`Workfile Dependency` default value can now be controlled from project settings.`Use Published Workfile` makes using published workfiles for rendering optional. + + +___ + +
+ +### **🐛 Bug fixes** + + +
+Maya: Attributes are locked after publishing if they are locked in Camera Family #6073 + +This PR is to make sure unlock attributes only during the bake context, make sure attributes are relocked after to preserve the lock state of the original node being baked. + + +___ + +
+ + +
+Missing nuke family Windows arguments #6131 + +Default Windows arguments for launching the Nuke family was missing. + + +___ + +
+ + +
+AYON: Fix the bug on the limit group not being set correctly in Maya Deadline Setting #6139 + +This PR is to bug-fix the limit groups from maya deadline settings errored out when the user tries to edit the setting. + + +___ + +
+ + +
+Chore: Transcoding extensions add missing '.tif' extension #6142 + +Image extensions in transcoding helper was missing `.tif` extension and had `.tiff` twice. + + +___ + +
+ + +
+Blender: Use the new API for override context #6145 + +Blender 4.0 disabled the old API to override context. This API updates the code to use the new API. + + +___ + +
+ + +
+BugFix: Include Model in FBX Loader in Houdini #6150 + +A quick bugfig where we can't load fbx exported from blender. The bug was reported here. + + +___ + +
+ + +
+Blender: Restore actions to objects after update #6153 + +Restore the actions assigned to objects after updating assets from blend files. + + +___ + +
+ + +
+Chore: Collect template data with hierarchy context #6154 + +Fixed queue loop where is used wrong variable to pop items from queue. + + +___ + +
+ + +
+OP-6382 - Thumbnail Integration Problem #6156 + +This ticket alerted to 3 different cases of integration issues; +- [x] Using the Tray Publisher with the same image format (extension) for representation and review representation. +- [x] Clash on publish file path from output definitions in `ExtractOIIOTranscode`. +- [x] Clash on publish file from thumbnail in `ExtractThumbnail`There might be an issue with this fix, if a studio does not use the `{output}` token in their `render` anatomy template. But thinking if they have customized it, they will be responsible to maintain these edge cases. + + +___ + +
+ + +
+Max: Bugfix saving camera scene errored out when creating render instance with multi-camera option turned off #6163 + +This PR is to make sure the integrator of saving camera scene turned off and the render submitted successfully when multi-camera options being turned off in 3dsmax + + +___ + +
+ + +
+Chore: Fix duplicated project name on create project structure #6166 + +Small fix in project folders. It is not used same variable name to change values which breaks values on any next loop. + + +___ + +
+ +### **Merged pull requests** + + +
+Maya: Remove duplicate plugin #6157 + +The two plugins below are doing the same work, so we can remove the one focused solely on lookdev.https://github.com/ynput/OpenPype/blob/develop/openpype/hosts/maya/plugins/publish/validate_look_members_unique.pyhttps://github.com/ynput/OpenPype/blob/develop/openpype/hosts/maya/plugins/publish/validate_node_ids_unique.py + + +___ + +
+ + +
+Publish report viewer: Report items sorting #6092 + +Proposal of items sorting in Publish report viewer tool. Items are sorted by report creation time. Creation time is also added to publish report data when saved from publisher tool. + + +___ + +
+ + +
+Maya: Extended error message #6161 + +Added more details to message + + +___ + +
+ + +
+Fusion: Added settings for Fusion creators to legacy OP #6162 + +Added missing OP variant of setting for new Fusion creator. + + +___ + +
+ + + + +## [3.18.4](https://github.com/ynput/OpenPype/tree/3.18.4) + + +[Full Changelog](https://github.com/ynput/OpenPype/compare/3.18.3...3.18.4) + +### **🚀 Enhancements** + + +
+multiple render camera supports for 3dsmax #5124 + +Supports for rendering with multiple cameras in 3dsmax +- [x] Add Batch Render Layers functions +- [x] Rewrite lib.rendersetting and lib.renderproduct +- [x] Add multi-camera options in creator. +- [x] Collector with batch render-layer when multi-camera enabled. +- [x] Add instance plugin for saving scene files with different cameras respectively by using subprocess +- [x] Refactor submit_max_deadline +- [x] Check with metadata.json in submit publish job + + +___ + +
+ + +
+Fusion: new creator for image product type #6057 + +In many DCC `render` product type is expected to be sequence of files. This PR adds new explicit creator for `image` product type which is focused on single frame image. Workflows for both product types might be a bit different, this gives artists more granularity to choose better workflow. + + +___ + +
+ +### **🐛 Bug fixes** + + +
+Maya: Account and ignore free image planes. #5993 + +Free image planes do not have the `->` path separator, so we need to account for that. + + +___ + +
+ + +
+Blender: Fix long names for instances #6070 + +Changed naming for instances to use only final part of the `folderPath`. + + +___ + +
+ + +
+Traypublisher & Chore: Instance version on follow workfile version #6117 + +If `follow_workfile_version` is enabled but context does not have filled workfile version, a version on instance is used instead. + + +___ + +
+ + +
+Substance Painter: Thumbnail errors with PBR Texture Set #6127 + +When publishing with PBR Metallic Roughness as Output Template, Emissive Map errors out because of the missing channel in the material and the map can't be generated in Substance Painter. This PR is to make sure `imagestance.data["publish"] = False` so that the related "empty" texture instance would be skipped to generate the output. + + +___ + +
+ + +
+Transcoding: Fix reading image sequences through oiiotool #6129 + +When transcoding image sequences, the second image onwards includes the invalid xml line of `Reading path/to/file.exr` of the oiiotool output.This is most likely not the best solution, but it fixes the issue and illustrates the problem.Error: +``` +ERROR:pyblish.plugin:Traceback (most recent call last): + File "C:\Users\tokejepsen\AppData\Local\Ynput\AYON\dependency_packages\ayon_2310271602_windows.zip\dependencies\pyblish\plugin.py", line 527, in __explicit_process + runner(*args) + File "C:\Users\tokejepsen\OpenPype\openpype\plugins\publish\extract_color_transcode.py", line 152, in process + File "C:\Users\tokejepsen\OpenPype\openpype\lib\transcoding.py", line 1136, in convert_colorspace + input_info = get_oiio_info_for_input(input_path, logger=logger) + File "C:\Users\tokejepsen\OpenPype\openpype\lib\transcoding.py", line 124, in get_oiio_info_for_input + output.append(parse_oiio_xml_output(xml_text, logger=logger)) + File "C:\Users\tokejepsen\OpenPype\openpype\lib\transcoding.py", line 276, in parse_oiio_xml_output + tree = xml.etree.ElementTree.fromstring(xml_string) + File "xml\etree\ElementTree.py", line 1347, in XML +xml.etree.ElementTree.ParseError: syntax error: line 1, column 0 +Traceback (most recent call last): + File "C:\Users\tokejepsen\AppData\Local\Ynput\AYON\dependency_packages\ayon_2310271602_windows.zip\dependencies\pyblish\plugin.py", line 527, in __explicit_process + runner(*args) + File "", line 152, in process + File "C:\Users\tokejepsen\OpenPype\openpype\lib\transcoding.py", line 1136, in convert_colorspace + input_info = get_oiio_info_for_input(input_path, logger=logger) + File "C:\Users\tokejepsen\OpenPype\openpype\lib\transcoding.py", line 124, in get_oiio_info_for_input + output.append(parse_oiio_xml_output(xml_text, logger=logger)) + File "C:\Users\tokejepsen\OpenPype\openpype\lib\transcoding.py", line 276, in parse_oiio_xml_output + tree = xml.etree.ElementTree.fromstring(xml_string) + File "xml\etree\ElementTree.py", line 1347, in XML +xml.etree.ElementTree.ParseError: syntax error: line 1, column 0 +``` + + + +___ + +
+ + +
+AYON: Remove 'IntegrateHeroVersion' conversion #6130 + +Remove settings conversion for `IntegrateHeroVersion`. + + +___ + +
+ + +
+Chore tools: Make sure style object is not garbage collected #6136 + +Minor fix in tool utils to make sure style C++ object is not garbage collected when not stored into variable. + + +___ + +
+ + + + ## [3.18.3](https://github.com/ynput/OpenPype/tree/3.18.3) diff --git a/openpype/hosts/blender/api/capture.py b/openpype/hosts/blender/api/capture.py index bad6831143..e5e6041563 100644 --- a/openpype/hosts/blender/api/capture.py +++ b/openpype/hosts/blender/api/capture.py @@ -127,8 +127,9 @@ def isolate_objects(window, objects): context = create_blender_context(selected=objects, window=window) - bpy.ops.view3d.view_axis(context, type="FRONT") - bpy.ops.view3d.localview(context) + with bpy.context.temp_override(**context): + bpy.ops.view3d.view_axis(type="FRONT") + bpy.ops.view3d.localview() deselect_all() @@ -270,10 +271,12 @@ def _independent_window(): """Create capture-window context.""" context = create_blender_context() current_windows = set(bpy.context.window_manager.windows) - bpy.ops.wm.window_new(context) - window = list(set(bpy.context.window_manager.windows) - current_windows)[0] - context["window"] = window - try: - yield window - finally: - bpy.ops.wm.window_close(context) + with bpy.context.temp_override(**context): + bpy.ops.wm.window_new() + window = list( + set(bpy.context.window_manager.windows) - current_windows)[0] + context["window"] = window + try: + yield window + finally: + bpy.ops.wm.window_close() diff --git a/openpype/hosts/blender/plugins/load/load_audio.py b/openpype/hosts/blender/plugins/load/load_audio.py index 1e5bd39a32..367fff03f0 100644 --- a/openpype/hosts/blender/plugins/load/load_audio.py +++ b/openpype/hosts/blender/plugins/load/load_audio.py @@ -67,7 +67,8 @@ class AudioLoader(plugin.AssetLoader): oc = bpy.context.copy() oc["area"] = window_manager.windows[-1].screen.areas[0] - bpy.ops.sequencer.sound_strip_add(oc, filepath=libpath, frame_start=1) + with bpy.context.temp_override(**oc): + bpy.ops.sequencer.sound_strip_add(filepath=libpath, frame_start=1) window_manager.windows[-1].screen.areas[0].type = old_type @@ -156,17 +157,18 @@ class AudioLoader(plugin.AssetLoader): oc = bpy.context.copy() oc["area"] = window_manager.windows[-1].screen.areas[0] - # We deselect all sequencer strips, and then select the one we - # need to remove. - bpy.ops.sequencer.select_all(oc, action='DESELECT') - scene = bpy.context.scene - scene.sequence_editor.sequences_all[old_audio].select = True + with bpy.context.temp_override(**oc): + # We deselect all sequencer strips, and then select the one we + # need to remove. + bpy.ops.sequencer.select_all(action='DESELECT') + scene = bpy.context.scene + scene.sequence_editor.sequences_all[old_audio].select = True - bpy.ops.sequencer.delete(oc) - bpy.data.sounds.remove(bpy.data.sounds[old_audio]) + bpy.ops.sequencer.delete() + bpy.data.sounds.remove(bpy.data.sounds[old_audio]) - bpy.ops.sequencer.sound_strip_add( - oc, filepath=str(libpath), frame_start=1) + bpy.ops.sequencer.sound_strip_add( + filepath=str(libpath), frame_start=1) window_manager.windows[-1].screen.areas[0].type = old_type @@ -205,12 +207,13 @@ class AudioLoader(plugin.AssetLoader): oc = bpy.context.copy() oc["area"] = window_manager.windows[-1].screen.areas[0] - # We deselect all sequencer strips, and then select the one we - # need to remove. - bpy.ops.sequencer.select_all(oc, action='DESELECT') - bpy.context.scene.sequence_editor.sequences_all[audio].select = True - - bpy.ops.sequencer.delete(oc) + with bpy.context.temp_override(**oc): + # We deselect all sequencer strips, and then select the one we + # need to remove. + bpy.ops.sequencer.select_all(action='DESELECT') + scene = bpy.context.scene + scene.sequence_editor.sequences_all[audio].select = True + bpy.ops.sequencer.delete() window_manager.windows[-1].screen.areas[0].type = old_type diff --git a/openpype/hosts/blender/plugins/load/load_blend.py b/openpype/hosts/blender/plugins/load/load_blend.py index 2d5ac18149..1a84f5afbb 100644 --- a/openpype/hosts/blender/plugins/load/load_blend.py +++ b/openpype/hosts/blender/plugins/load/load_blend.py @@ -102,7 +102,6 @@ class BlendLoader(plugin.AssetLoader): # Link all the container children to the collection for obj in container.children_recursive: - print(obj) bpy.context.scene.collection.objects.link(obj) # Remove the library from the blend file @@ -194,8 +193,20 @@ class BlendLoader(plugin.AssetLoader): transform = asset_group.matrix_basis.copy() old_data = dict(asset_group.get(AVALON_PROPERTY)) + old_members = old_data.get("members", []) parent = asset_group.parent + actions = {} + objects_with_anim = [ + obj for obj in asset_group.children_recursive + if obj.animation_data] + for obj in objects_with_anim: + # Check if the object has an action and, if so, add it to a dict + # so we can restore it later. Save and restore the action only + # if it wasn't originally loaded from the current asset. + if obj.animation_data.action not in old_members: + actions[obj.name] = obj.animation_data.action + self.exec_remove(container) asset_group, members = self._process_data(libpath, group_name) @@ -206,6 +217,13 @@ class BlendLoader(plugin.AssetLoader): asset_group.matrix_basis = transform asset_group.parent = parent + # Restore the actions + for obj in asset_group.children_recursive: + if obj.name in actions: + if not obj.animation_data: + obj.animation_data_create() + obj.animation_data.action = actions[obj.name] + # Restore the old data, but reset memebers, as they don't exist anymore # This avoids a crash, because the memory addresses of those members # are not valid anymore diff --git a/openpype/hosts/blender/plugins/publish/extract_abc_animation.py b/openpype/hosts/blender/plugins/publish/extract_abc_animation.py index 6ef9b29693..2bf75aa05e 100644 --- a/openpype/hosts/blender/plugins/publish/extract_abc_animation.py +++ b/openpype/hosts/blender/plugins/publish/extract_abc_animation.py @@ -55,13 +55,13 @@ class ExtractAnimationABC( context = plugin.create_blender_context( active=asset_group, selected=selected) - # We export the abc - bpy.ops.wm.alembic_export( - context, - filepath=filepath, - selected=True, - flatten=False - ) + with bpy.context.temp_override(**context): + # We export the abc + bpy.ops.wm.alembic_export( + filepath=filepath, + selected=True, + flatten=False + ) plugin.deselect_all() diff --git a/openpype/hosts/blender/plugins/publish/extract_camera_fbx.py b/openpype/hosts/blender/plugins/publish/extract_camera_fbx.py index ee046b7d11..f904b79ddb 100644 --- a/openpype/hosts/blender/plugins/publish/extract_camera_fbx.py +++ b/openpype/hosts/blender/plugins/publish/extract_camera_fbx.py @@ -50,19 +50,19 @@ class ExtractCamera(publish.Extractor, publish.OptionalPyblishPluginMixin): scale_length = bpy.context.scene.unit_settings.scale_length bpy.context.scene.unit_settings.scale_length = 0.01 - # We export the fbx - bpy.ops.export_scene.fbx( - context, - filepath=filepath, - use_active_collection=False, - use_selection=True, - bake_anim_use_nla_strips=False, - bake_anim_use_all_actions=False, - add_leaf_bones=False, - armature_nodetype='ROOT', - object_types={'CAMERA'}, - bake_anim_simplify_factor=0.0 - ) + with bpy.context.temp_override(**context): + # We export the fbx + bpy.ops.export_scene.fbx( + filepath=filepath, + use_active_collection=False, + use_selection=True, + bake_anim_use_nla_strips=False, + bake_anim_use_all_actions=False, + add_leaf_bones=False, + armature_nodetype='ROOT', + object_types={'CAMERA'}, + bake_anim_simplify_factor=0.0 + ) bpy.context.scene.unit_settings.scale_length = scale_length diff --git a/openpype/hosts/blender/plugins/publish/extract_fbx.py b/openpype/hosts/blender/plugins/publish/extract_fbx.py index 4ae6501f7d..aed6df1d3d 100644 --- a/openpype/hosts/blender/plugins/publish/extract_fbx.py +++ b/openpype/hosts/blender/plugins/publish/extract_fbx.py @@ -57,15 +57,15 @@ class ExtractFBX(publish.Extractor, publish.OptionalPyblishPluginMixin): scale_length = bpy.context.scene.unit_settings.scale_length bpy.context.scene.unit_settings.scale_length = 0.01 - # We export the fbx - bpy.ops.export_scene.fbx( - context, - filepath=filepath, - use_active_collection=False, - use_selection=True, - mesh_smooth_type='FACE', - add_leaf_bones=False - ) + with bpy.context.temp_override(**context): + # We export the fbx + bpy.ops.export_scene.fbx( + filepath=filepath, + use_active_collection=False, + use_selection=True, + mesh_smooth_type='FACE', + add_leaf_bones=False + ) bpy.context.scene.unit_settings.scale_length = scale_length diff --git a/openpype/hosts/blender/plugins/publish/extract_fbx_animation.py b/openpype/hosts/blender/plugins/publish/extract_fbx_animation.py index 4fc8230a1b..1cb8dac0cf 100644 --- a/openpype/hosts/blender/plugins/publish/extract_fbx_animation.py +++ b/openpype/hosts/blender/plugins/publish/extract_fbx_animation.py @@ -153,17 +153,20 @@ class ExtractAnimationFBX( override = plugin.create_blender_context( active=root, selected=[root, armature]) - bpy.ops.export_scene.fbx( - override, - filepath=filepath, - use_active_collection=False, - use_selection=True, - bake_anim_use_nla_strips=False, - bake_anim_use_all_actions=False, - add_leaf_bones=False, - armature_nodetype='ROOT', - object_types={'EMPTY', 'ARMATURE'} - ) + + with bpy.context.temp_override(**override): + # We export the fbx + bpy.ops.export_scene.fbx( + filepath=filepath, + use_active_collection=False, + use_selection=True, + bake_anim_use_nla_strips=False, + bake_anim_use_all_actions=False, + add_leaf_bones=False, + armature_nodetype='ROOT', + object_types={'EMPTY', 'ARMATURE'} + ) + armature.name = armature_name asset_group.name = asset_group_name root.select_set(True) diff --git a/openpype/hosts/blender/plugins/publish/extract_layout.py b/openpype/hosts/blender/plugins/publish/extract_layout.py index 3e8978c8d3..383c3bdcc5 100644 --- a/openpype/hosts/blender/plugins/publish/extract_layout.py +++ b/openpype/hosts/blender/plugins/publish/extract_layout.py @@ -80,17 +80,18 @@ class ExtractLayout(publish.Extractor, publish.OptionalPyblishPluginMixin): override = plugin.create_blender_context( active=asset, selected=[asset, obj]) - bpy.ops.export_scene.fbx( - override, - filepath=filepath, - use_active_collection=False, - use_selection=True, - bake_anim_use_nla_strips=False, - bake_anim_use_all_actions=False, - add_leaf_bones=False, - armature_nodetype='ROOT', - object_types={'EMPTY', 'ARMATURE'} - ) + with bpy.context.temp_override(**override): + # We export the fbx + bpy.ops.export_scene.fbx( + filepath=filepath, + use_active_collection=False, + use_selection=True, + bake_anim_use_nla_strips=False, + bake_anim_use_all_actions=False, + add_leaf_bones=False, + armature_nodetype='ROOT', + object_types={'EMPTY', 'ARMATURE'} + ) obj.name = armature_name asset.name = asset_group_name asset.select_set(False) diff --git a/openpype/hosts/fusion/plugins/publish/validate_saver_resolution.py b/openpype/hosts/fusion/plugins/publish/validate_saver_resolution.py index f6aba170c0..b28af3409d 100644 --- a/openpype/hosts/fusion/plugins/publish/validate_saver_resolution.py +++ b/openpype/hosts/fusion/plugins/publish/validate_saver_resolution.py @@ -8,55 +8,6 @@ from openpype.hosts.fusion.api.action import SelectInvalidAction from openpype.hosts.fusion.api import comp_lock_and_undo_chunk -def get_tool_resolution(tool, frame): - """Return the 2D input resolution to a Fusion tool - - If the current tool hasn't been rendered its input resolution - hasn't been saved. To combat this, add an expression in - the comments field to read the resolution - - Args - tool (Fusion Tool): The tool to query input resolution - frame (int): The frame to query the resolution on. - - Returns: - tuple: width, height as 2-tuple of integers - - """ - comp = tool.Composition - - # False undo removes the undo-stack from the undo list - with comp_lock_and_undo_chunk(comp, "Read resolution", False): - # Save old comment - old_comment = "" - has_expression = False - if tool["Comments"][frame] != "": - if tool["Comments"].GetExpression() is not None: - has_expression = True - old_comment = tool["Comments"].GetExpression() - tool["Comments"].SetExpression(None) - else: - old_comment = tool["Comments"][frame] - tool["Comments"][frame] = "" - - # Get input width - tool["Comments"].SetExpression("self.Input.OriginalWidth") - width = int(tool["Comments"][frame]) - - # Get input height - tool["Comments"].SetExpression("self.Input.OriginalHeight") - height = int(tool["Comments"][frame]) - - # Reset old comment - tool["Comments"].SetExpression(None) - if has_expression: - tool["Comments"].SetExpression(old_comment) - else: - tool["Comments"][frame] = old_comment - - return width, height - - class ValidateSaverResolution( pyblish.api.InstancePlugin, OptionalPyblishPluginMixin ): @@ -87,19 +38,79 @@ class ValidateSaverResolution( @classmethod def get_invalid(cls, instance): - resolution = cls.get_resolution(instance) + saver = instance.data["tool"] + try: + resolution = cls.get_resolution(instance) + except PublishValidationError: + resolution = None expected_resolution = cls.get_expected_resolution(instance) if resolution != expected_resolution: - saver = instance.data["tool"] return [saver] @classmethod def get_resolution(cls, instance): saver = instance.data["tool"] first_frame = instance.data["frameStartHandle"] - return get_tool_resolution(saver, frame=first_frame) + return cls.get_tool_resolution(saver, frame=first_frame) @classmethod def get_expected_resolution(cls, instance): data = instance.data["assetEntity"]["data"] return data["resolutionWidth"], data["resolutionHeight"] + + @classmethod + def get_tool_resolution(cls, tool, frame): + """Return the 2D input resolution to a Fusion tool + + If the current tool hasn't been rendered its input resolution + hasn't been saved. To combat this, add an expression in + the comments field to read the resolution + + Args + tool (Fusion Tool): The tool to query input resolution + frame (int): The frame to query the resolution on. + + Returns: + tuple: width, height as 2-tuple of integers + + """ + comp = tool.Composition + + # False undo removes the undo-stack from the undo list + with comp_lock_and_undo_chunk(comp, "Read resolution", False): + # Save old comment + old_comment = "" + has_expression = False + + if tool["Comments"][frame] not in ["", None]: + if tool["Comments"].GetExpression() is not None: + has_expression = True + old_comment = tool["Comments"].GetExpression() + tool["Comments"].SetExpression(None) + else: + old_comment = tool["Comments"][frame] + tool["Comments"][frame] = "" + # Get input width + tool["Comments"].SetExpression("self.Input.OriginalWidth") + if tool["Comments"][frame] is None: + raise PublishValidationError( + "Cannot get resolution info for frame '{}'.\n\n " + "Please check that saver has connected input.".format( + frame + ) + ) + + width = int(tool["Comments"][frame]) + + # Get input height + tool["Comments"].SetExpression("self.Input.OriginalHeight") + height = int(tool["Comments"][frame]) + + # Reset old comment + tool["Comments"].SetExpression(None) + if has_expression: + tool["Comments"].SetExpression(old_comment) + else: + tool["Comments"][frame] = old_comment + + return width, height diff --git a/openpype/hosts/hiero/plugins/publish/collect_clip_effects.py b/openpype/hosts/hiero/plugins/publish/collect_clip_effects.py index fcb1ab27a0..d7f646ebc9 100644 --- a/openpype/hosts/hiero/plugins/publish/collect_clip_effects.py +++ b/openpype/hosts/hiero/plugins/publish/collect_clip_effects.py @@ -9,6 +9,8 @@ class CollectClipEffects(pyblish.api.InstancePlugin): label = "Collect Clip Effects Instances" families = ["clip"] + effect_categories = [] + def process(self, instance): family = "effect" effects = {} @@ -70,29 +72,62 @@ class CollectClipEffects(pyblish.api.InstancePlugin): subset_split.insert(0, "effect") - name = "".join(subset_split) + effect_categories = { + x["name"]: x["effect_classes"] for x in self.effect_categories + } - # create new instance and inherit data - data = {} - for key, value in instance.data.items(): - if "clipEffectItems" in key: + category_by_effect = {"": ""} + for key, values in effect_categories.items(): + for cls in values: + category_by_effect[cls] = key + + effects_categorized = {k: {} for k in effect_categories.keys()} + effects_categorized[""] = {} + for key, value in effects.items(): + if key == "assignTo": continue - data[key] = value - # change names - data["subset"] = name - data["family"] = family - data["families"] = [family] - data["name"] = data["subset"] + "_" + data["asset"] - data["label"] = "{} - {}".format( - data['asset'], data["subset"] - ) - data["effects"] = effects + # Some classes can have a number in them. Like Text2. + found_cls = "" + for cls in category_by_effect.keys(): + if cls in value["class"]: + found_cls = cls - # create new instance - _instance = instance.context.create_instance(**data) - self.log.info("Created instance `{}`".format(_instance)) - self.log.debug("instance.data `{}`".format(_instance.data)) + effects_categorized[category_by_effect[found_cls]][key] = value + + categories = list(effects_categorized.keys()) + for category in categories: + if not effects_categorized[category]: + effects_categorized.pop(category) + continue + + effects_categorized[category]["assignTo"] = effects["assignTo"] + + for category, effects in effects_categorized.items(): + name = "".join(subset_split) + name += category.capitalize() + + # create new instance and inherit data + data = {} + for key, value in instance.data.items(): + if "clipEffectItems" in key: + continue + data[key] = value + + # change names + data["subset"] = name + data["family"] = family + data["families"] = [family] + data["name"] = data["subset"] + "_" + data["asset"] + data["label"] = "{} - {}".format( + data['asset'], data["subset"] + ) + data["effects"] = effects + + # create new instance + _instance = instance.context.create_instance(**data) + self.log.info("Created instance `{}`".format(_instance)) + self.log.debug("instance.data `{}`".format(_instance.data)) def test_overlap(self, effect_t_in, effect_t_out): covering_exp = bool( diff --git a/openpype/hosts/houdini/plugins/load/load_fbx.py b/openpype/hosts/houdini/plugins/load/load_fbx.py index cac22d62d4..894ac62b3e 100644 --- a/openpype/hosts/houdini/plugins/load/load_fbx.py +++ b/openpype/hosts/houdini/plugins/load/load_fbx.py @@ -16,8 +16,9 @@ class FbxLoader(load.LoaderPlugin): order = -10 - families = ["staticMesh", "fbx"] - representations = ["fbx"] + families = ["*"] + representations = ["*"] + extensions = {"fbx"} def load(self, context, name=None, namespace=None, data=None): diff --git a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py index c39109417b..f089bf663c 100644 --- a/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py +++ b/openpype/hosts/max/plugins/publish/save_scenes_for_cameras.py @@ -21,6 +21,11 @@ class SaveScenesForCamera(pyblish.api.InstancePlugin): families = ["maxrender"] def process(self, instance): + if not instance.data.get("multiCamera"): + self.log.debug( + "Multi Camera disabled. " + "Skipping to save scene files for cameras") + return current_folder = rt.maxFilePath current_filename = rt.maxFileName current_filepath = os.path.join(current_folder, current_filename) diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 394f92ed42..da34896c3f 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -2778,9 +2778,37 @@ def bake_to_world_space(nodes, list: The newly created and baked node names. """ + @contextlib.contextmanager + def _unlock_attr(attr): + """Unlock attribute during context if it is locked""" + if not cmds.getAttr(attr, lock=True): + # If not locked, do nothing + yield + return + try: + cmds.setAttr(attr, lock=False) + yield + finally: + cmds.setAttr(attr, lock=True) def _get_attrs(node): - """Workaround for buggy shape attribute listing with listAttr""" + """Workaround for buggy shape attribute listing with listAttr + + This will only return keyable settable attributes that have an + incoming connections (those that have a reason to be baked). + + Technically this *may* fail to return attributes driven by complex + expressions for which maya makes no connections, e.g. doing actual + `setAttr` calls in expressions. + + Arguments: + node (str): The node to list attributes for. + + Returns: + list: Keyable attributes with incoming connections. + The attribute may be locked. + + """ attrs = cmds.listAttr(node, write=True, scalar=True, @@ -2805,14 +2833,14 @@ def bake_to_world_space(nodes, return valid_attrs - transform_attrs = set(["t", "r", "s", - "tx", "ty", "tz", - "rx", "ry", "rz", - "sx", "sy", "sz"]) + transform_attrs = {"t", "r", "s", + "tx", "ty", "tz", + "rx", "ry", "rz", + "sx", "sy", "sz"} world_space_nodes = [] - with delete_after() as delete_bin: - + with ExitStack() as stack: + delete_bin = stack.enter_context(delete_after()) # Create the duplicate nodes that are in world-space connected to # the originals for node in nodes: @@ -2824,23 +2852,26 @@ def bake_to_world_space(nodes, name=new_name, renameChildren=True)[0] # noqa - # Connect all attributes on the node except for transform - # attributes - attrs = _get_attrs(node) - attrs = set(attrs) - transform_attrs if attrs else [] + # Parent new node to world + if cmds.listRelatives(new_node, parent=True): + new_node = cmds.parent(new_node, world=True)[0] + # Temporarily unlock and passthrough connect all attributes + # so we can bake them over time + # Skip transform attributes because we will constrain them later + attrs = set(_get_attrs(node)) - transform_attrs for attr in attrs: - orig_node_attr = '{0}.{1}'.format(node, attr) - new_node_attr = '{0}.{1}'.format(new_node, attr) - - # unlock to avoid connection errors - cmds.setAttr(new_node_attr, lock=False) + orig_node_attr = "{}.{}".format(node, attr) + new_node_attr = "{}.{}".format(new_node, attr) + # unlock during context to avoid connection errors + stack.enter_context(_unlock_attr(new_node_attr)) cmds.connectAttr(orig_node_attr, new_node_attr, force=True) - # If shapes are also baked then connect those keyable attributes + # If shapes are also baked then also temporarily unlock and + # passthrough connect all shape attributes for baking if shape: children_shapes = cmds.listRelatives(new_node, children=True, @@ -2855,25 +2886,19 @@ def bake_to_world_space(nodes, children_shapes): attrs = _get_attrs(orig_shape) for attr in attrs: - orig_node_attr = '{0}.{1}'.format(orig_shape, attr) - new_node_attr = '{0}.{1}'.format(new_shape, attr) - - # unlock to avoid connection errors - cmds.setAttr(new_node_attr, lock=False) + orig_node_attr = "{}.{}".format(orig_shape, attr) + new_node_attr = "{}.{}".format(new_shape, attr) + # unlock during context to avoid connection errors + stack.enter_context(_unlock_attr(new_node_attr)) cmds.connectAttr(orig_node_attr, new_node_attr, force=True) - # Parent to world - if cmds.listRelatives(new_node, parent=True): - new_node = cmds.parent(new_node, world=True)[0] - - # Unlock transform attributes so constraint can be created + # Constraint transforms for attr in transform_attrs: - cmds.setAttr('{0}.{1}'.format(new_node, attr), lock=False) - - # Constraints + transform_attr = "{}.{}".format(new_node, attr) + stack.enter_context(_unlock_attr(transform_attr)) delete_bin.extend(cmds.parentConstraint(node, new_node, mo=False)) delete_bin.extend(cmds.scaleConstraint(node, new_node, mo=False)) diff --git a/openpype/hosts/maya/plugins/publish/extract_camera_mayaScene.py b/openpype/hosts/maya/plugins/publish/extract_camera_mayaScene.py index 38cf00bbdd..f67e9db14f 100644 --- a/openpype/hosts/maya/plugins/publish/extract_camera_mayaScene.py +++ b/openpype/hosts/maya/plugins/publish/extract_camera_mayaScene.py @@ -265,13 +265,16 @@ def transfer_image_planes(source_cameras, target_cameras, try: for source_camera, target_camera in zip(source_cameras, target_cameras): - image_planes = cmds.listConnections(source_camera, + image_plane_plug = "{}.imagePlane".format(source_camera) + image_planes = cmds.listConnections(image_plane_plug, + source=True, + destination=False, type="imagePlane") or [] # Split of the parent path they are attached - we want - # the image plane node name. + # the image plane node name if attached to a camera. # TODO: Does this still mean the image plane name is unique? - image_planes = [x.split("->", 1)[1] for x in image_planes] + image_planes = [x.split("->", 1)[-1] for x in image_planes] if not image_planes: continue @@ -282,7 +285,7 @@ def transfer_image_planes(source_cameras, target_cameras, if source_camera == target_camera: continue _attach_image_plane(target_camera, image_plane) - else: # explicitly dettaching image planes + else: # explicitly detach image planes cmds.imagePlane(image_plane, edit=True, detach=True) originals[source_camera].append(image_plane) yield diff --git a/openpype/hosts/maya/plugins/publish/validate_look_members_unique.py b/openpype/hosts/maya/plugins/publish/validate_look_members_unique.py deleted file mode 100644 index 4e01b55249..0000000000 --- a/openpype/hosts/maya/plugins/publish/validate_look_members_unique.py +++ /dev/null @@ -1,77 +0,0 @@ -from collections import defaultdict - -import pyblish.api - -import openpype.hosts.maya.api.action -from openpype.pipeline.publish import ( - PublishValidationError, ValidatePipelineOrder) - - -class ValidateUniqueRelationshipMembers(pyblish.api.InstancePlugin): - """Validate the relational nodes of the look data to ensure every node is - unique. - - This ensures the all member ids are unique. Every node id must be from - a single node in the scene. - - That means there's only ever one of a specific node inside the look to be - published. For example if you'd have a loaded 3x the same tree and by - accident you're trying to publish them all together in a single look that - would be invalid, because they are the same tree. It should be included - inside the look instance only once. - - """ - - order = ValidatePipelineOrder - label = 'Look members unique' - hosts = ['maya'] - families = ['look'] - - actions = [openpype.hosts.maya.api.action.SelectInvalidAction, - openpype.hosts.maya.api.action.GenerateUUIDsOnInvalidAction] - - def process(self, instance): - """Process all meshes""" - - invalid = self.get_invalid(instance) - if invalid: - raise PublishValidationError( - ("Members found without non-unique IDs: " - "{0}").format(invalid)) - - @staticmethod - def get_invalid(instance): - """ - Check all the relationship members of the objectSets - - Example of the lookData relationships: - {"uuid": 59b2bb27bda2cb2776206dd8:79ab0a63ffdf, - "members":[{"uuid": 59b2bb27bda2cb2776206dd8:1b158cc7496e, - "name": |model_GRP|body_GES|body_GESShape} - ..., - ...]} - - Args: - instance: - - Returns: - - """ - - # Get all members from the sets - id_nodes = defaultdict(set) - relationships = instance.data["lookData"]["relationships"] - - for relationship in relationships.values(): - for member in relationship['members']: - node_id = member["uuid"] - node = member["name"] - id_nodes[node_id].add(node) - - # Check if any id has more than 1 node - invalid = [] - for nodes in id_nodes.values(): - if len(nodes) > 1: - invalid.extend(nodes) - - return invalid diff --git a/openpype/hosts/maya/plugins/publish/validate_scene_set_workspace.py b/openpype/hosts/maya/plugins/publish/validate_scene_set_workspace.py index b48d67e416..ddcbab8931 100644 --- a/openpype/hosts/maya/plugins/publish/validate_scene_set_workspace.py +++ b/openpype/hosts/maya/plugins/publish/validate_scene_set_workspace.py @@ -44,4 +44,8 @@ class ValidateSceneSetWorkspace(pyblish.api.ContextPlugin): if not is_subdir(scene_name, root_dir): raise PublishValidationError( - "Maya workspace is not set correctly.") + "Maya workspace is not set correctly.\n\n" + f"Current workfile `{scene_name}` is not inside the " + "current Maya project root directory `{root_dir}`.\n\n" + "Please use Workfile app to re-save." + ) diff --git a/openpype/hosts/traypublisher/plugins/publish/collect_simple_instances.py b/openpype/hosts/traypublisher/plugins/publish/collect_simple_instances.py index 3fa3c3b8c8..d6e35f4d75 100644 --- a/openpype/hosts/traypublisher/plugins/publish/collect_simple_instances.py +++ b/openpype/hosts/traypublisher/plugins/publish/collect_simple_instances.py @@ -216,6 +216,11 @@ class CollectSettingsSimpleInstances(pyblish.api.InstancePlugin): instance.data["thumbnailSource"] = first_filepath review_representation["tags"].append("review") + + # Adding "review" to representation name since it can clash with main + # representation if they share the same extension. + review_representation["outputName"] = "review" + self.log.debug("Representation {} was marked for review. {}".format( review_representation["name"], review_path )) diff --git a/openpype/lib/connections.py b/openpype/lib/connections.py index 91b745a4c1..6a0cf4ae1c 100644 --- a/openpype/lib/connections.py +++ b/openpype/lib/connections.py @@ -6,13 +6,13 @@ def requests_post(*args, **kwargs): """Wrap request post method. Disabling SSL certificate validation if ``DONT_VERIFY_SSL`` environment - variable is found. This is useful when Deadline or Muster server are - running with self-signed certificates and their certificate is not + variable is found. This is useful when Deadline server is + running with self-signed certificates and its certificate is not added to trusted certificates on client machines. Warning: Disabling SSL certificate validation is defeating one line - of defense SSL is providing and it is not recommended. + of defense SSL is providing, and it is not recommended. """ if "verify" not in kwargs: @@ -24,13 +24,13 @@ def requests_get(*args, **kwargs): """Wrap request get method. Disabling SSL certificate validation if ``DONT_VERIFY_SSL`` environment - variable is found. This is useful when Deadline or Muster server are - running with self-signed certificates and their certificate is not + variable is found. This is useful when Deadline server is + running with self-signed certificates and its certificate is not added to trusted certificates on client machines. Warning: Disabling SSL certificate validation is defeating one line - of defense SSL is providing and it is not recommended. + of defense SSL is providing, and it is not recommended. """ if "verify" not in kwargs: diff --git a/openpype/lib/transcoding.py b/openpype/lib/transcoding.py index 03fd91bec2..c8ddbde061 100644 --- a/openpype/lib/transcoding.py +++ b/openpype/lib/transcoding.py @@ -44,17 +44,17 @@ XML_CHAR_REF_REGEX_HEX = re.compile(r"&#x?[0-9a-fA-F]+;") ARRAY_TYPE_REGEX = re.compile(r"^(int|float|string)\[\d+\]$") IMAGE_EXTENSIONS = { - ".ani", ".anim", ".apng", ".art", ".bmp", ".bpg", ".bsave", ".cal", - ".cin", ".cpc", ".cpt", ".dds", ".dpx", ".ecw", ".exr", ".fits", - ".flic", ".flif", ".fpx", ".gif", ".hdri", ".hevc", ".icer", - ".icns", ".ico", ".cur", ".ics", ".ilbm", ".jbig", ".jbig2", - ".jng", ".jpeg", ".jpeg-ls", ".jpeg", ".2000", ".jpg", ".xr", - ".jpeg", ".xt", ".jpeg-hdr", ".kra", ".mng", ".miff", ".nrrd", - ".ora", ".pam", ".pbm", ".pgm", ".ppm", ".pnm", ".pcx", ".pgf", - ".pictor", ".png", ".psd", ".psb", ".psp", ".qtvr", ".ras", - ".rgbe", ".logluv", ".tiff", ".sgi", ".tga", ".tiff", ".tiff/ep", - ".tiff/it", ".ufo", ".ufp", ".wbmp", ".webp", ".xbm", ".xcf", - ".xpm", ".xwd" + ".ani", ".anim", ".apng", ".art", ".bmp", ".bpg", ".bsave", + ".cal", ".cin", ".cpc", ".cpt", ".dds", ".dpx", ".ecw", ".exr", + ".fits", ".flic", ".flif", ".fpx", ".gif", ".hdri", ".hevc", + ".icer", ".icns", ".ico", ".cur", ".ics", ".ilbm", ".jbig", ".jbig2", + ".jng", ".jpeg", ".jpeg-ls", ".jpeg-hdr", ".2000", ".jpg", + ".kra", ".logluv", ".mng", ".miff", ".nrrd", ".ora", + ".pam", ".pbm", ".pgm", ".ppm", ".pnm", ".pcx", ".pgf", + ".pictor", ".png", ".psd", ".psb", ".psp", ".qtvr", + ".ras", ".rgbe", ".sgi", ".tga", + ".tif", ".tiff", ".tiff/ep", ".tiff/it", ".ufo", ".ufp", + ".wbmp", ".webp", ".xr", ".xt", ".xbm", ".xcf", ".xpm", ".xwd" } VIDEO_EXTENSIONS = { diff --git a/openpype/modules/base.py b/openpype/modules/base.py index 1a2513b4b4..cb64816cc9 100644 --- a/openpype/modules/base.py +++ b/openpype/modules/base.py @@ -542,7 +542,8 @@ def _load_modules(): module_dirs.insert(0, current_dir) addons_dir = os.path.join(os.path.dirname(current_dir), "addons") - module_dirs.append(addons_dir) + if os.path.exists(addons_dir): + module_dirs.append(addons_dir) ignored_host_names = set(IGNORED_HOSTS_IN_AYON) ignored_current_dir_filenames = set(IGNORED_DEFAULT_FILENAMES) @@ -1332,7 +1333,6 @@ class TrayModulesManager(ModulesManager): "user", "ftrack", "kitsu", - "muster", "launcher_tool", "avalon", "clockify", diff --git a/openpype/modules/deadline/abstract_submit_deadline.py b/openpype/modules/deadline/abstract_submit_deadline.py index 002dfa5992..b0d5d7f222 100644 --- a/openpype/modules/deadline/abstract_submit_deadline.py +++ b/openpype/modules/deadline/abstract_submit_deadline.py @@ -34,8 +34,8 @@ def requests_post(*args, **kwargs): """Wrap request post method. Disabling SSL certificate validation if ``DONT_VERIFY_SSL`` environment - variable is found. This is useful when Deadline or Muster server are - running with self-signed certificates and their certificate is not + variable is found. This is useful when Deadline server is + running with self-signed certificates and its certificate is not added to trusted certificates on client machines. Warning: @@ -55,8 +55,8 @@ def requests_get(*args, **kwargs): """Wrap request get method. Disabling SSL certificate validation if ``DONT_VERIFY_SSL`` environment - variable is found. This is useful when Deadline or Muster server are - running with self-signed certificates and their certificate is not + variable is found. This is useful when Deadline server is + running with self-signed certificates and its certificate is not added to trusted certificates on client machines. Warning: diff --git a/openpype/modules/deadline/plugins/publish/submit_nuke_deadline.py b/openpype/modules/deadline/plugins/publish/submit_nuke_deadline.py index d03416ca00..746b009255 100644 --- a/openpype/modules/deadline/plugins/publish/submit_nuke_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_nuke_deadline.py @@ -47,6 +47,7 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin, env_allowed_keys = [] env_search_replace_values = {} workfile_dependency = True + use_published_workfile = True @classmethod def get_attribute_defs(cls): @@ -85,8 +86,13 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin, ), BoolDef( "workfile_dependency", - default=True, + default=cls.workfile_dependency, label="Workfile Dependency" + ), + BoolDef( + "use_published_workfile", + default=cls.use_published_workfile, + label="Use Published Workfile" ) ] @@ -125,20 +131,11 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin, render_path = instance.data['path'] script_path = context.data["currentFile"] - for item_ in context: - if "workfile" in item_.data["family"]: - template_data = item_.data.get("anatomyData") - rep = item_.data.get("representations")[0].get("name") - template_data["representation"] = rep - template_data["ext"] = rep - template_data["comment"] = None - anatomy_filled = context.data["anatomy"].format(template_data) - template_filled = anatomy_filled["publish"]["path"] - script_path = os.path.normpath(template_filled) - - self.log.info( - "Using published scene for render {}".format(script_path) - ) + use_published_workfile = instance.data["attributeValues"].get( + "use_published_workfile", self.use_published_workfile + ) + if use_published_workfile: + script_path = self._get_published_workfile_path(context) # only add main rendering job if target is not frames_farm r_job_response_json = None @@ -197,6 +194,44 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin, families.insert(0, "prerender") instance.data["families"] = families + def _get_published_workfile_path(self, context): + """This method is temporary while the class is not inherited from + AbstractSubmitDeadline""" + for instance in context: + if ( + instance.data["family"] != "workfile" + # Disabled instances won't be integrated + or instance.data("publish") is False + ): + continue + template_data = instance.data["anatomyData"] + # Expect workfile instance has only one representation + representation = instance.data["representations"][0] + # Get workfile extension + repre_file = representation["files"] + self.log.info(repre_file) + ext = os.path.splitext(repre_file)[1].lstrip(".") + + # Fill template data + template_data["representation"] = representation["name"] + template_data["ext"] = ext + template_data["comment"] = None + + anatomy = context.data["anatomy"] + # WARNING Hardcoded template name 'publish' > may not be used + template_obj = anatomy.templates_obj["publish"]["path"] + + template_filled = template_obj.format(template_data) + script_path = os.path.normpath(template_filled) + self.log.info( + "Using published scene for render {}".format( + script_path + ) + ) + return script_path + + return None + def payload_submit( self, instance, diff --git a/openpype/modules/deadline/plugins/publish/submit_publish_cache_job.py b/openpype/modules/deadline/plugins/publish/submit_publish_cache_job.py index b2ebebc303..1bb45b77cc 100644 --- a/openpype/modules/deadline/plugins/publish/submit_publish_cache_job.py +++ b/openpype/modules/deadline/plugins/publish/submit_publish_cache_job.py @@ -99,10 +99,6 @@ class ProcessSubmittedCacheJobOnFarm(pyblish.api.InstancePlugin, def _submit_deadline_post_job(self, instance, job): """Submit publish job to Deadline. - Deadline specific code separated from :meth:`process` for sake of - more universal code. Muster post job is sent directly by Muster - submitter, so this type of code isn't necessary for it. - Returns: (str): deadline_publish_job_id """ diff --git a/openpype/modules/deadline/plugins/publish/submit_publish_job.py b/openpype/modules/deadline/plugins/publish/submit_publish_job.py index 04ce2b3433..82971daee5 100644 --- a/openpype/modules/deadline/plugins/publish/submit_publish_job.py +++ b/openpype/modules/deadline/plugins/publish/submit_publish_job.py @@ -59,21 +59,15 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin, publish.ColormanagedPyblishPluginMixin): """Process Job submitted on farm. - These jobs are dependent on a deadline or muster job + These jobs are dependent on a deadline job submission prior to this plug-in. - - In case of Deadline, it creates dependent job on farm publishing - rendered image sequence. - - - In case of Muster, there is no need for such thing as dependent job, - post action will be executed and rendered sequence will be published. + It creates dependent job on farm publishing rendered image sequence. Options in instance.data: - deadlineSubmissionJob (dict, Required): The returned .json data from the job submission to deadline. - - musterSubmissionJob (dict, Required): same as deadline. - - outputDir (str, Required): The output directory where the metadata file should be generated. It's assumed that this will also be final folder containing the output files. @@ -161,10 +155,6 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin, def _submit_deadline_post_job(self, instance, job, instances): """Submit publish job to Deadline. - Deadline specific code separated from :meth:`process` for sake of - more universal code. Muster post job is sent directly by Muster - submitter, so this type of code isn't necessary for it. - Returns: (str): deadline_publish_job_id """ @@ -586,9 +576,8 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin, render_job = instance.data.pop("deadlineSubmissionJob", None) if not render_job and instance.data.get("tileRendering") is False: - raise AssertionError(("Cannot continue without valid Deadline " - "or Muster submission.")) - + raise AssertionError(("Cannot continue without valid " + "Deadline submission.")) if not render_job: import getpass diff --git a/openpype/modules/muster/__init__.py b/openpype/modules/muster/__init__.py deleted file mode 100644 index d194f8f3c2..0000000000 --- a/openpype/modules/muster/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from .muster import MusterModule - - -__all__ = ( - "MusterModule", -) diff --git a/openpype/modules/muster/muster.py b/openpype/modules/muster/muster.py deleted file mode 100644 index 0cdb1230c8..0000000000 --- a/openpype/modules/muster/muster.py +++ /dev/null @@ -1,147 +0,0 @@ -import os -import json - -import appdirs -import requests - -from openpype.modules import OpenPypeModule, ITrayModule - - -class MusterModule(OpenPypeModule, ITrayModule): - """ - Module handling Muster Render credentials. This will display dialog - asking for user credentials for Muster if not already specified. - """ - cred_folder_path = os.path.normpath( - appdirs.user_data_dir('pype-app', 'pype') - ) - cred_filename = 'muster_cred.json' - - name = "muster" - - def initialize(self, modules_settings): - muster_settings = modules_settings[self.name] - self.enabled = muster_settings["enabled"] - self.muster_url = muster_settings["MUSTER_REST_URL"] - - self.cred_path = os.path.join( - self.cred_folder_path, self.cred_filename - ) - # Tray attributes - self.widget_login = None - self.action_show_login = None - self.rest_api_obj = None - - def get_global_environments(self): - return { - "MUSTER_REST_URL": self.muster_url - } - - def tray_init(self): - from .widget_login import MusterLogin - self.widget_login = MusterLogin(self) - - def tray_start(self): - """Show login dialog if credentials not found.""" - # This should be start of module in tray - cred = self.load_credentials() - if not cred: - self.show_login() - - def tray_exit(self): - """Nothing special for Muster.""" - return - - # Definition of Tray menu - def tray_menu(self, parent): - """Add **change credentials** option to tray menu.""" - from qtpy import QtWidgets - - # Menu for Tray App - menu = QtWidgets.QMenu('Muster', parent) - menu.setProperty('submenu', 'on') - - # Actions - self.action_show_login = QtWidgets.QAction( - "Change login", menu - ) - - menu.addAction(self.action_show_login) - self.action_show_login.triggered.connect(self.show_login) - - parent.addMenu(menu) - - def load_credentials(self): - """ - Get credentials from JSON file - """ - credentials = {} - try: - file = open(self.cred_path, 'r') - credentials = json.load(file) - except Exception: - file = open(self.cred_path, 'w+') - file.close() - - return credentials - - def get_auth_token(self, username, password): - """ - Authenticate user with Muster and get authToken from server. - """ - if not self.muster_url: - raise AttributeError("Muster REST API url not set") - params = { - 'username': username, - 'password': password - } - api_entry = '/api/login' - response = self._requests_post( - self.muster_url + api_entry, params=params) - if response.status_code != 200: - self.log.error( - 'Cannot log into Muster: {}'.format(response.status_code)) - raise Exception('Cannot login into Muster.') - - try: - token = response.json()['ResponseData']['authToken'] - except ValueError as e: - self.log.error('Invalid response from Muster server {}'.format(e)) - raise Exception('Invalid response from Muster while logging in.') - - self.save_credentials(token) - - def save_credentials(self, token): - """Save credentials to JSON file.""" - - with open(self.cred_path, "w") as f: - json.dump({'token': token}, f) - - def show_login(self): - """ - Show dialog to enter credentials - """ - if self.widget_login: - self.widget_login.show() - - # Webserver module implementation - def webserver_initialization(self, server_manager): - """Add routes for Muster login.""" - if self.tray_initialized: - from .rest_api import MusterModuleRestApi - - self.rest_api_obj = MusterModuleRestApi(self, server_manager) - - def _requests_post(self, *args, **kwargs): - """ Wrapper for requests, disabling SSL certificate validation if - DONT_VERIFY_SSL environment variable is found. This is useful when - Deadline or Muster server are running with self-signed certificates - and their certificate is not added to trusted certificates on - client machines. - - WARNING: disabling SSL certificate validation is defeating one line - of defense SSL is providing and it is not recommended. - """ - if 'verify' not in kwargs: - kwargs['verify'] = False if os.getenv("OPENPYPE_DONT_VERIFY_SSL", True) else True # noqa - return requests.post(*args, **kwargs) diff --git a/openpype/modules/muster/plugins/publish/submit_maya_muster.py b/openpype/modules/muster/plugins/publish/submit_maya_muster.py deleted file mode 100644 index f6b3bfbbfd..0000000000 --- a/openpype/modules/muster/plugins/publish/submit_maya_muster.py +++ /dev/null @@ -1,555 +0,0 @@ -import os -import json -import getpass -import platform - -import appdirs - -from maya import cmds - -import pyblish.api -from openpype.lib import requests_post -from openpype.hosts.maya.api import lib -from openpype.hosts.maya.api.lib_rendersettings import RenderSettings -from openpype.pipeline import legacy_io -from openpype.settings import get_system_settings - - -# mapping between Maya renderer names and Muster template ids -def _get_template_id(renderer): - """ - Return muster template ID based on renderer name. - - :param renderer: renderer name - :type renderer: str - :returns: muster template id - :rtype: int - """ - - # TODO: Use settings from context? - templates = get_system_settings()["modules"]["muster"]["templates_mapping"] - if not templates: - raise RuntimeError(("Muster template mapping missing in " - "pype-settings")) - try: - template_id = templates[renderer] - except KeyError: - raise RuntimeError("Unmapped renderer - missing template id") - - return template_id - - -def _get_script(): - """Get path to the image sequence script""" - try: - from openpype.scripts import publish_filesequence - except Exception: - raise RuntimeError("Expected module 'publish_deadline'" - "to be available") - - module_path = publish_filesequence.__file__ - if module_path.endswith(".pyc"): - module_path = module_path[:-len(".pyc")] + ".py" - - return module_path - - -def get_renderer_variables(renderlayer=None): - """Retrieve the extension which has been set in the VRay settings - - Will return None if the current renderer is not VRay - For Maya 2016.5 and up the renderSetup creates renderSetupLayer node which - start with `rs`. Use the actual node name, do NOT use the `nice name` - - Args: - renderlayer (str): the node name of the renderlayer. - - Returns: - dict - """ - - renderer = lib.get_renderer(renderlayer or lib.get_current_renderlayer()) - - padding = cmds.getAttr(RenderSettings.get_padding_attr(renderer)) - - filename_0 = cmds.renderSettings(fullPath=True, firstImageName=True)[0] - - if renderer == "vray": - # Maya's renderSettings function does not return V-Ray file extension - # so we get the extension from vraySettings - extension = cmds.getAttr("vraySettings.imageFormatStr") - - # When V-Ray image format has not been switched once from default .png - # the getAttr command above returns None. As such we explicitly set - # it to `.png` - if extension is None: - extension = "png" - - filename_prefix = "/_/" - else: - # Get the extension, getAttr defaultRenderGlobals.imageFormat - # returns an index number. - filename_base = os.path.basename(filename_0) - extension = os.path.splitext(filename_base)[-1].strip(".") - filename_prefix = "//" - - return {"ext": extension, - "filename_prefix": filename_prefix, - "padding": padding, - "filename_0": filename_0} - - -def preview_fname(folder, scene, layer, padding, ext): - """Return output file path with #### for padding. - - Deadline requires the path to be formatted with # in place of numbers. - For example `/path/to/render.####.png` - - Args: - folder (str): The root output folder (image path) - scene (str): The scene name - layer (str): The layer name to be rendered - padding (int): The padding length - ext(str): The output file extension - - Returns: - str - - """ - - # Following hardcoded "/_/" - output = "{scene}/{layer}/{layer}.{number}.{ext}".format( - scene=scene, - layer=layer, - number="#" * padding, - ext=ext - ) - - return os.path.join(folder, output) - - -class MayaSubmitMuster(pyblish.api.InstancePlugin): - """Submit available render layers to Muster - - Renders are submitted to a Muster via HTTP API as - supplied via the environment variable ``MUSTER_REST_URL``. - - Also needed is ``MUSTER_USER`` and ``MUSTER_PASSWORD``. - """ - - label = "Submit to Muster" - order = pyblish.api.IntegratorOrder + 0.1 - hosts = ["maya"] - families = ["renderlayer"] - icon = "satellite-dish" - if not os.environ.get("MUSTER_REST_URL"): - optional = False - active = False - else: - optional = True - - _token = None - - def _load_credentials(self): - """ - Load Muster credentials from file and set `MUSTER_USER`, - `MUSTER_PASSWORD`, `MUSTER_REST_URL` is loaded from settings. - - .. todo:: - - Show login dialog if access token is invalid or missing. - """ - app_dir = os.path.normpath( - appdirs.user_data_dir('pype-app', 'pype') - ) - file_name = 'muster_cred.json' - fpath = os.path.join(app_dir, file_name) - file = open(fpath, 'r') - muster_json = json.load(file) - self._token = muster_json.get('token', None) - if not self._token: - raise RuntimeError("Invalid access token for Muster") - file.close() - self.MUSTER_REST_URL = os.environ.get("MUSTER_REST_URL") - if not self.MUSTER_REST_URL: - raise AttributeError("Muster REST API url not set") - - def _get_templates(self): - """ - Get Muster templates from server. - """ - params = { - "authToken": self._token, - "select": "name" - } - api_entry = '/api/templates/list' - response = requests_post( - self.MUSTER_REST_URL + api_entry, params=params) - if response.status_code != 200: - self.log.error( - 'Cannot get templates from Muster: {}'.format( - response.status_code)) - raise Exception('Cannot get templates from Muster.') - - try: - response_templates = response.json()["ResponseData"]["templates"] - except ValueError as e: - self.log.error( - 'Muster server returned unexpected data {}'.format(e) - ) - raise Exception('Muster server returned unexpected data') - - templates = {} - for t in response_templates: - templates[t.get("name")] = t.get("id") - - self._templates = templates - - def _resolve_template(self, renderer): - """ - Returns template ID based on renderer string. - - :param renderer: Name of renderer to match against template names - :type renderer: str - :returns: ID of template - :rtype: int - :raises: Exception if template ID isn't found - """ - self.log.debug("Trying to find template for [{}]".format(renderer)) - mapped = _get_template_id(renderer) - self.log.debug("got id [{}]".format(mapped)) - return self._templates.get(mapped) - - def _submit(self, payload): - """ - Submit job to Muster - - :param payload: json with job to submit - :type payload: str - :returns: response - :raises: Exception status is wrong - """ - params = { - "authToken": self._token, - "name": "submit" - } - api_entry = '/api/queue/actions' - response = requests_post( - self.MUSTER_REST_URL + api_entry, params=params, json=payload) - - if response.status_code != 200: - self.log.error( - 'Cannot submit job to Muster: {}'.format(response.text)) - raise Exception('Cannot submit job to Muster.') - - return response - - def process(self, instance): - """ - Authenticate with Muster, collect all data, prepare path for post - render publish job and submit job to farm. - """ - # setup muster environment - self.MUSTER_REST_URL = os.environ.get("MUSTER_REST_URL") - - if self.MUSTER_REST_URL is None: - self.log.error( - "\"MUSTER_REST_URL\" is not found. Skipping " - "[{}]".format(instance) - ) - raise RuntimeError("MUSTER_REST_URL not set") - - self._load_credentials() - # self._get_templates() - - context = instance.context - workspace = context.data["workspaceDir"] - project_name = context.data["projectName"] - asset_name = context.data["asset"] - - filepath = None - - allInstances = [] - for result in context.data["results"]: - if ((result["instance"] is not None) and - (result["instance"] not in allInstances)): - allInstances.append(result["instance"]) - - for inst in allInstances: - print(inst) - if inst.data['family'] == 'scene': - filepath = inst.data['destination_list'][0] - - if not filepath: - filepath = context.data["currentFile"] - - self.log.debug(filepath) - - filename = os.path.basename(filepath) - comment = context.data.get("comment", "") - scene = os.path.splitext(filename)[0] - dirname = os.path.join(workspace, "renders") - renderlayer = instance.data['renderlayer'] # rs_beauty - renderlayer_name = instance.data['subset'] # beauty - renderglobals = instance.data["renderGlobals"] - # legacy_layers = renderlayer_globals["UseLegacyRenderLayers"] - # deadline_user = context.data.get("deadlineUser", getpass.getuser()) - jobname = "%s - %s" % (filename, instance.name) - - # Get the variables depending on the renderer - render_variables = get_renderer_variables(renderlayer) - output_filename_0 = preview_fname(folder=dirname, - scene=scene, - layer=renderlayer_name, - padding=render_variables["padding"], - ext=render_variables["ext"]) - - instance.data["outputDir"] = os.path.dirname(output_filename_0) - self.log.debug("output: {}".format(filepath)) - # build path for metadata file - metadata_filename = "{}_metadata.json".format(instance.data["subset"]) - output_dir = instance.data["outputDir"] - metadata_path = os.path.join(output_dir, metadata_filename) - - pype_root = os.environ["OPENPYPE_SETUP_PATH"] - - # we must provide either full path to executable or use musters own - # python named MPython.exe, residing directly in muster bin - # directory. - if platform.system().lower() == "windows": - # for muster, those backslashes must be escaped twice - muster_python = ("\"C:\\\\Program Files\\\\Virtual Vertex\\\\" - "Muster 9\\\\MPython.exe\"") - else: - # we need to run pype as different user then Muster dispatcher - # service is running (usually root). - muster_python = ("/usr/sbin/runuser -u {}" - " -- /usr/bin/python3".format(getpass.getuser())) - - # build the path and argument. We are providing separate --pype - # argument with network path to pype as post job actions are run - # but dispatcher (Server) and not render clients. Render clients - # inherit environment from publisher including PATH, so there's - # no problem finding PYPE, but there is now way (as far as I know) - # to set environment dynamically for dispatcher. Therefore this hack. - args = [muster_python, - _get_script().replace('\\', '\\\\'), - "--paths", - metadata_path.replace('\\', '\\\\'), - "--pype", - pype_root.replace('\\', '\\\\')] - - postjob_command = " ".join(args) - - try: - # Ensure render folder exists - os.makedirs(dirname) - except OSError: - pass - - env = self.clean_environment() - - payload = { - "RequestData": { - "platform": 0, - "job": { - "jobName": jobname, - "templateId": _get_template_id( - instance.data["renderer"]), - "chunksInterleave": 2, - "chunksPriority": "0", - "chunksTimeoutValue": 320, - "department": "", - "dependIds": [""], - "dependLinkMode": 0, - "dependMode": 0, - "emergencyQueue": False, - "excludedPools": [""], - "includedPools": [renderglobals["Pool"]], - "packetSize": 4, - "packetType": 1, - "priority": 1, - "jobId": -1, - "startOn": 0, - "parentId": -1, - "project": project_name or scene, - "shot": asset_name or scene, - "camera": instance.data.get("cameras")[0], - "dependMode": 0, - "packetSize": 4, - "packetType": 1, - "priority": 1, - "maximumInstances": 0, - "assignedInstances": 0, - "attributes": { - "environmental_variables": { - "value": ", ".join("{!s}={!r}".format(k, v) - for (k, v) in env.items()), - - "state": True, - "subst": False - }, - "memo": { - "value": comment, - "state": True, - "subst": False - }, - "frames_range": { - "value": "{start}-{end}".format( - start=int(instance.data["frameStart"]), - end=int(instance.data["frameEnd"])), - "state": True, - "subst": False - }, - "job_file": { - "value": filepath, - "state": True, - "subst": True - }, - "job_project": { - "value": workspace, - "state": True, - "subst": True - }, - "output_folder": { - "value": dirname.replace("\\", "/"), - "state": True, - "subst": True - }, - "post_job_action": { - "value": postjob_command, - "state": True, - "subst": True - }, - "MAYADIGITS": { - "value": 1, - "state": True, - "subst": False - }, - "ARNOLDMODE": { - "value": "0", - "state": True, - "subst": False - }, - "ABORTRENDER": { - "value": "0", - "state": True, - "subst": True - }, - "ARNOLDLICENSE": { - "value": "0", - "state": False, - "subst": False - }, - "ADD_FLAGS": { - "value": "-rl {}".format(renderlayer), - "state": True, - "subst": True - } - } - } - } - } - - self.preflight_check(instance) - - self.log.debug("Submitting ...") - self.log.debug(json.dumps(payload, indent=4, sort_keys=True)) - - response = self._submit(payload) - # response = requests.post(url, json=payload) - if not response.ok: - raise Exception(response.text) - - # Store output dir for unified publisher (filesequence) - - instance.data["musterSubmissionJob"] = response.json() - - def clean_environment(self): - """ - Clean and set environment variables for render job so render clients - work in more or less same environment as publishing machine. - - .. warning:: This is not usable for **post job action** as this is - executed on dispatcher machine (server) and not render clients. - """ - keys = [ - # This will trigger `userSetup.py` on the slave - # such that proper initialisation happens the same - # way as it does on a local machine. - # TODO(marcus): This won't work if the slaves don't - # have access to these paths, such as if slaves are - # running Linux and the submitter is on Windows. - "PYTHONPATH", - "PATH", - - "MTOA_EXTENSIONS_PATH", - "MTOA_EXTENSIONS", - "DYLD_LIBRARY_PATH", - "MAYA_RENDER_DESC_PATH", - "MAYA_MODULE_PATH", - "ARNOLD_PLUGIN_PATH", - "FTRACK_API_KEY", - "FTRACK_API_USER", - "FTRACK_SERVER", - "PYBLISHPLUGINPATH", - - # todo: This is a temporary fix for yeti variables - "PEREGRINEL_LICENSE", - "SOLIDANGLE_LICENSE", - "ARNOLD_LICENSE" - "MAYA_MODULE_PATH", - "TOOL_ENV" - ] - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) - # self.log.debug("enviro: {}".format(pprint(environment))) - for path in os.environ: - if path.lower().startswith('pype_'): - environment[path] = os.environ[path] - - environment["PATH"] = os.environ["PATH"] - # self.log.debug("enviro: {}".format(environment['OPENPYPE_SCRIPTS'])) - clean_environment = {} - for key, value in environment.items(): - clean_path = "" - self.log.debug("key: {}".format(key)) - if "://" in value: - clean_path = value - else: - valid_paths = [] - for path in value.split(os.pathsep): - if not path: - continue - try: - path.decode('UTF-8', 'strict') - valid_paths.append(os.path.normpath(path)) - except UnicodeDecodeError: - print('path contains non UTF characters') - - if valid_paths: - clean_path = os.pathsep.join(valid_paths) - - clean_environment[key] = clean_path - - return clean_environment - - def preflight_check(self, instance): - """Ensure the startFrame, endFrame and byFrameStep are integers""" - - for key in ("frameStart", "frameEnd", "byFrameStep"): - value = instance.data[key] - - if int(value) == value: - continue - - self.log.warning( - "%f=%d was rounded off to nearest integer" - % (value, int(value)) - ) - - -# TODO: Remove hack to avoid this plug-in in new publisher -# This plug-in should actually be in dedicated module -if not os.environ.get("MUSTER_REST_URL"): - del MayaSubmitMuster diff --git a/openpype/modules/muster/plugins/publish/validate_muster_connection.py b/openpype/modules/muster/plugins/publish/validate_muster_connection.py deleted file mode 100644 index c31ccf405c..0000000000 --- a/openpype/modules/muster/plugins/publish/validate_muster_connection.py +++ /dev/null @@ -1,96 +0,0 @@ -import os -import json - -import appdirs - -import pyblish.api -from openpype.lib import requests_get -from openpype.pipeline.publish import ( - context_plugin_should_run, - RepairAction, -) - - -class ValidateMusterConnection(pyblish.api.ContextPlugin): - """ - Validate Muster REST API Service is running and we have valid auth token - """ - - label = "Validate Muster REST API Service" - order = pyblish.api.ValidatorOrder - hosts = ["maya"] - families = ["renderlayer"] - token = None - if not os.environ.get("MUSTER_REST_URL"): - active = False - actions = [RepairAction] - - def process(self, context): - - # Workaround bug pyblish-base#250 - if not context_plugin_should_run(self, context): - return - - # test if we have environment set (redundant as this plugin shouldn' - # be active otherwise). - try: - MUSTER_REST_URL = os.environ["MUSTER_REST_URL"] - except KeyError: - self.log.error("Muster REST API url not found.") - raise ValueError("Muster REST API url not found.") - - # Load credentials - try: - self._load_credentials() - except RuntimeError: - self.log.error("invalid or missing access token") - - assert self._token is not None, "Invalid or missing token" - - # We have token, lets do trivial query to web api to see if we can - # connect and access token is valid. - params = { - 'authToken': self._token - } - api_entry = '/api/pools/list' - response = requests_get( - MUSTER_REST_URL + api_entry, params=params) - assert response.status_code == 200, "invalid response from server" - assert response.json()['ResponseData'], "invalid data in response" - - def _load_credentials(self): - """ - Load Muster credentials from file and set `MUSTER_USER`, - `MUSTER_PASSWORD`, `MUSTER_REST_URL` is loaded from settings. - - .. todo:: - - Show login dialog if access token is invalid or missing. - """ - app_dir = os.path.normpath( - appdirs.user_data_dir('pype-app', 'pype') - ) - file_name = 'muster_cred.json' - fpath = os.path.join(app_dir, file_name) - file = open(fpath, 'r') - muster_json = json.load(file) - self._token = muster_json.get('token', None) - if not self._token: - raise RuntimeError("Invalid access token for Muster") - file.close() - self.MUSTER_REST_URL = os.environ.get("MUSTER_REST_URL") - if not self.MUSTER_REST_URL: - raise AttributeError("Muster REST API url not set") - - @classmethod - def repair(cls, instance): - """ - Renew authentication token by logging into Muster - """ - api_url = "{}/muster/show_login".format( - os.environ["OPENPYPE_WEBSERVER_URL"]) - cls.log.debug(api_url) - response = requests_get(api_url, timeout=1) - if response.status_code != 200: - cls.log.error('Cannot show login form to Muster') - raise Exception('Cannot show login form to Muster') diff --git a/openpype/modules/muster/rest_api.py b/openpype/modules/muster/rest_api.py deleted file mode 100644 index bea759919d..0000000000 --- a/openpype/modules/muster/rest_api.py +++ /dev/null @@ -1,22 +0,0 @@ -from aiohttp.web_response import Response - - -class MusterModuleRestApi: - def __init__(self, user_module, server_manager): - self.module = user_module - self.server_manager = server_manager - - self.prefix = "/muster" - - self.register() - - def register(self): - self.server_manager.add_route( - "GET", - self.prefix + "/show_login", - self.show_login_widget - ) - - async def show_login_widget(self, request): - self.module.action_show_login.trigger() - return Response(status=200) diff --git a/openpype/modules/muster/widget_login.py b/openpype/modules/muster/widget_login.py deleted file mode 100644 index f38f43fb7f..0000000000 --- a/openpype/modules/muster/widget_login.py +++ /dev/null @@ -1,165 +0,0 @@ -from qtpy import QtCore, QtGui, QtWidgets -from openpype import resources, style - - -class MusterLogin(QtWidgets.QWidget): - - SIZE_W = 300 - SIZE_H = 150 - - loginSignal = QtCore.Signal(object, object, object) - - def __init__(self, module, parent=None): - - super(MusterLogin, self).__init__(parent) - - self.module = module - - # Icon - icon = QtGui.QIcon(resources.get_openpype_icon_filepath()) - self.setWindowIcon(icon) - - self.setWindowFlags( - QtCore.Qt.WindowCloseButtonHint | - QtCore.Qt.WindowMinimizeButtonHint - ) - - self._translate = QtCore.QCoreApplication.translate - - # Font - self.font = QtGui.QFont() - self.font.setFamily("DejaVu Sans Condensed") - self.font.setPointSize(9) - self.font.setBold(True) - self.font.setWeight(50) - self.font.setKerning(True) - - # Size setting - self.resize(self.SIZE_W, self.SIZE_H) - self.setMinimumSize(QtCore.QSize(self.SIZE_W, self.SIZE_H)) - self.setMaximumSize(QtCore.QSize(self.SIZE_W+100, self.SIZE_H+100)) - self.setStyleSheet(style.load_stylesheet()) - - self.setLayout(self._main()) - self.setWindowTitle('Muster login') - - def _main(self): - self.main = QtWidgets.QVBoxLayout() - self.main.setObjectName("main") - - self.form = QtWidgets.QFormLayout() - self.form.setContentsMargins(10, 15, 10, 5) - self.form.setObjectName("form") - - self.label_username = QtWidgets.QLabel("Username:") - self.label_username.setFont(self.font) - self.label_username.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) - self.label_username.setTextFormat(QtCore.Qt.RichText) - - self.input_username = QtWidgets.QLineEdit() - self.input_username.setEnabled(True) - self.input_username.setFrame(True) - self.input_username.setPlaceholderText( - self._translate("main", "e.g. John Smith") - ) - - self.label_password = QtWidgets.QLabel("Password:") - self.label_password.setFont(self.font) - self.label_password.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) - self.label_password.setTextFormat(QtCore.Qt.RichText) - - self.input_password = QtWidgets.QLineEdit() - self.input_password.setEchoMode(QtWidgets.QLineEdit.Password) - self.input_password.setEnabled(True) - self.input_password.setFrame(True) - self.input_password.setPlaceholderText( - self._translate("main", "e.g. ********") - ) - - self.error_label = QtWidgets.QLabel("") - self.error_label.setFont(self.font) - self.error_label.setStyleSheet('color: #FC6000') - self.error_label.setWordWrap(True) - self.error_label.hide() - - self.form.addRow(self.label_username, self.input_username) - self.form.addRow(self.label_password, self.input_password) - self.form.addRow(self.error_label) - - self.btn_group = QtWidgets.QHBoxLayout() - self.btn_group.addStretch(1) - self.btn_group.setObjectName("btn_group") - - self.btn_ok = QtWidgets.QPushButton("Ok") - self.btn_ok.clicked.connect(self.click_ok) - - self.btn_cancel = QtWidgets.QPushButton("Cancel") - QtWidgets.QShortcut( - QtGui.QKeySequence( - QtCore.Qt.Key_Escape), self).activated.connect(self.close) - self.btn_cancel.clicked.connect(self.close) - - self.btn_group.addWidget(self.btn_ok) - self.btn_group.addWidget(self.btn_cancel) - - self.main.addLayout(self.form) - self.main.addLayout(self.btn_group) - - return self.main - - def keyPressEvent(self, key_event): - if key_event.key() == QtCore.Qt.Key_Return: - if self.input_username.hasFocus(): - self.input_password.setFocus() - - elif self.input_password.hasFocus() or self.btn_ok.hasFocus(): - self.click_ok() - - elif self.btn_cancel.hasFocus(): - self.close() - else: - super().keyPressEvent(key_event) - - def setError(self, msg): - self.error_label.setText(msg) - self.error_label.show() - - def invalid_input(self, entity): - entity.setStyleSheet("border: 1px solid red;") - - def click_ok(self): - # all what should happen - validations and saving into appsdir - username = self.input_username.text() - password = self.input_password.text() - # TODO: more robust validation. Password can be empty in muster? - if not username: - self.setError("Username cannot be empty") - self.invalid_input(self.input_username) - try: - self.save_credentials(username, password) - except Exception as e: - self.setError( - "Cannot get auth token:\n{}".format(e)) - else: - self._close_widget() - - def save_credentials(self, username, password): - self.module.get_auth_token(username, password) - - def showEvent(self, event): - super(MusterLogin, self).showEvent(event) - - # Make btns same width - max_width = max( - self.btn_ok.sizeHint().width(), - self.btn_cancel.sizeHint().width() - ) - self.btn_ok.setMinimumWidth(max_width) - self.btn_cancel.setMinimumWidth(max_width) - - def closeEvent(self, event): - event.ignore() - self._close_widget() - - def _close_widget(self): - self.hide() diff --git a/openpype/pipeline/project_folders.py b/openpype/pipeline/project_folders.py index 1bcba5c320..608344ce03 100644 --- a/openpype/pipeline/project_folders.py +++ b/openpype/pipeline/project_folders.py @@ -28,13 +28,20 @@ def concatenate_splitted_paths(split_paths, anatomy): # backward compatibility if "__project_root__" in path_items: for root, root_path in anatomy.roots.items(): - if not os.path.exists(str(root_path)): - log.debug("Root {} path path {} not exist on \ - computer!".format(root, root_path)) + if not root_path or not os.path.exists(str(root_path)): + log.debug( + "Root {} path path {} not exist on computer!".format( + root, root_path + ) + ) continue - clean_items = ["{{root[{}]}}".format(root), - r"{project[name]}"] + clean_items[1:] - output.append(os.path.normpath(os.path.sep.join(clean_items))) + + root_items = [ + "{{root[{}]}}".format(root), + "{project[name]}" + ] + root_items.extend(clean_items[1:]) + output.append(os.path.normpath(os.path.sep.join(root_items))) continue output.append(os.path.normpath(os.path.sep.join(clean_items))) diff --git a/openpype/pipeline/workfile/workfile_template_builder.py b/openpype/pipeline/workfile/workfile_template_builder.py index 9dc833061a..3096d22518 100644 --- a/openpype/pipeline/workfile/workfile_template_builder.py +++ b/openpype/pipeline/workfile/workfile_template_builder.py @@ -1971,7 +1971,6 @@ class PlaceholderCreateMixin(object): if not placeholder.data.get("keep_placeholder", True): self.delete_placeholder(placeholder) - def create_failed(self, placeholder, creator_data): if hasattr(placeholder, "create_failed"): placeholder.create_failed(creator_data) @@ -2036,7 +2035,7 @@ class CreatePlaceholderItem(PlaceholderItem): self._failed_created_publish_instances = [] def get_errors(self): - if not self._failed_representations: + if not self._failed_created_publish_instances: return [] message = ( "Failed to create {} instance using Creator {}" diff --git a/openpype/plugins/publish/collect_anatomy_instance_data.py b/openpype/plugins/publish/collect_anatomy_instance_data.py index 34df49ea5b..b1b7ecd138 100644 --- a/openpype/plugins/publish/collect_anatomy_instance_data.py +++ b/openpype/plugins/publish/collect_anatomy_instance_data.py @@ -410,9 +410,9 @@ class CollectAnatomyInstanceData(pyblish.api.ContextPlugin): """ hierarchy_queue = collections.deque() - hierarchy_queue.append(hierarchy_context) + hierarchy_queue.append(copy.deepcopy(hierarchy_context)) while hierarchy_queue: - item = hierarchy_context.popleft() + item = hierarchy_queue.popleft() if asset_name in item: return item[asset_name].get("tasks") or {} diff --git a/openpype/plugins/publish/collect_farm_target.py b/openpype/plugins/publish/collect_farm_target.py index adcd842b48..2f77c823d7 100644 --- a/openpype/plugins/publish/collect_farm_target.py +++ b/openpype/plugins/publish/collect_farm_target.py @@ -19,7 +19,7 @@ class CollectFarmTarget(pyblish.api.InstancePlugin): farm_name = "" op_modules = context.data.get("openPypeModules") - for farm_renderer in ["deadline", "royalrender", "muster"]: + for farm_renderer in ["deadline", "royalrender"]: op_module = op_modules.get(farm_renderer, False) if op_module and op_module.enabled: diff --git a/openpype/plugins/publish/collect_rendered_files.py b/openpype/plugins/publish/collect_rendered_files.py index 6160b4f5c8..baaf454a11 100644 --- a/openpype/plugins/publish/collect_rendered_files.py +++ b/openpype/plugins/publish/collect_rendered_files.py @@ -93,14 +93,6 @@ class CollectRenderedFiles(pyblish.api.ContextPlugin): assert ctx.get("user") == data.get("user"), ctx_err % "user" assert ctx.get("version") == data.get("version"), ctx_err % "version" - # ftrack credentials are passed as environment variables by Deadline - # to publish job, but Muster doesn't pass them. - if data.get("ftrack") and not os.environ.get("FTRACK_API_USER"): - ftrack = data.get("ftrack") - os.environ["FTRACK_API_USER"] = ftrack["FTRACK_API_USER"] - os.environ["FTRACK_API_KEY"] = ftrack["FTRACK_API_KEY"] - os.environ["FTRACK_SERVER"] = ftrack["FTRACK_SERVER"] - # now we can just add instances from json file and we are done any_staging_dir_persistent = False for instance_data in data.get("instances"): diff --git a/openpype/plugins/publish/extract_color_transcode.py b/openpype/plugins/publish/extract_color_transcode.py index faacb7af2e..922df469fe 100644 --- a/openpype/plugins/publish/extract_color_transcode.py +++ b/openpype/plugins/publish/extract_color_transcode.py @@ -189,6 +189,13 @@ class ExtractOIIOTranscode(publish.Extractor): if len(new_repre["files"]) == 1: new_repre["files"] = new_repre["files"][0] + # If the source representation has "review" tag, but its not + # part of the output defintion tags, then both the + # representations will be transcoded in ExtractReview and + # their outputs will clash in integration. + if "review" in repre.get("tags", []): + added_review = True + new_representations.append(new_repre) added_representations = True diff --git a/openpype/plugins/publish/extract_hierarchy_to_ayon.py b/openpype/plugins/publish/extract_hierarchy_to_ayon.py index b601a3fc29..9e84daca30 100644 --- a/openpype/plugins/publish/extract_hierarchy_to_ayon.py +++ b/openpype/plugins/publish/extract_hierarchy_to_ayon.py @@ -30,8 +30,7 @@ class ExtractHierarchyToAYON(pyblish.api.ContextPlugin): if not AYON_SERVER_ENABLED: return - hierarchy_context = context.data.get("hierarchyContext") - if not hierarchy_context: + if not context.data.get("hierarchyContext"): self.log.debug("Skipping ExtractHierarchyToAYON") return diff --git a/openpype/plugins/publish/extract_thumbnail.py b/openpype/plugins/publish/extract_thumbnail.py index 2b4ea0529a..10eb261482 100644 --- a/openpype/plugins/publish/extract_thumbnail.py +++ b/openpype/plugins/publish/extract_thumbnail.py @@ -231,7 +231,10 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): "files": jpeg_file, "stagingDir": dst_staging, "thumbnail": True, - "tags": new_repre_tags + "tags": new_repre_tags, + # If source image is jpg then there can be clash when + # integrating to making the output name explicit. + "outputName": "thumbnail" } # adding representation diff --git a/openpype/settings/ayon_settings.py b/openpype/settings/ayon_settings.py index 36f96c9dc7..4948f2431c 100644 --- a/openpype/settings/ayon_settings.py +++ b/openpype/settings/ayon_settings.py @@ -220,22 +220,6 @@ def _convert_deadline_system_settings( output["modules"]["deadline"] = deadline_settings -def _convert_muster_system_settings( - ayon_settings, output, addon_versions, default_settings -): - enabled = addon_versions.get("muster") is not None - muster_settings = default_settings["modules"]["muster"] - muster_settings["enabled"] = enabled - if enabled: - ayon_muster = ayon_settings["muster"] - muster_settings["MUSTER_REST_URL"] = ayon_muster["MUSTER_REST_URL"] - muster_settings["templates_mapping"] = { - item["name"]: item["value"] - for item in ayon_muster["templates_mapping"] - } - output["modules"]["muster"] = muster_settings - - def _convert_royalrender_system_settings( ayon_settings, output, addon_versions, default_settings ): @@ -261,7 +245,6 @@ def _convert_modules_system( _convert_timers_manager_system_settings, _convert_clockify_system_settings, _convert_deadline_system_settings, - _convert_muster_system_settings, _convert_royalrender_system_settings, ): func(ayon_settings, output, addon_versions, default_settings) @@ -1236,6 +1219,8 @@ def _convert_global_project_settings(ayon_settings, output, default_settings): for profile in extract_oiio_transcode_profiles: new_outputs = {} name_counter = {} + if "product_names" in profile: + profile["subsets"] = profile.pop("product_names") for profile_output in profile["outputs"]: if "name" in profile_output: name = profile_output.pop("name") diff --git a/openpype/settings/defaults/project_settings/deadline.json b/openpype/settings/defaults/project_settings/deadline.json index a19464a5c1..b02cfa8207 100644 --- a/openpype/settings/defaults/project_settings/deadline.json +++ b/openpype/settings/defaults/project_settings/deadline.json @@ -65,6 +65,8 @@ "group": "", "department": "", "use_gpu": true, + "workfile_dependency": true, + "use_published_workfile": true, "env_allowed_keys": [], "env_search_replace_values": {}, "limit_groups": {} diff --git a/openpype/settings/defaults/project_settings/fusion.json b/openpype/settings/defaults/project_settings/fusion.json index 15b6bfc09b..f890f94b6f 100644 --- a/openpype/settings/defaults/project_settings/fusion.json +++ b/openpype/settings/defaults/project_settings/fusion.json @@ -31,7 +31,8 @@ "reviewable", "farm_rendering" ], - "image_format": "exr" + "image_format": "exr", + "default_frame_range_option": "asset_db" }, "CreateImageSaver": { "temp_rendering_path_template": "{workdir}/renders/fusion/{subset}/{subset}.{ext}", @@ -43,7 +44,8 @@ "reviewable", "farm_rendering" ], - "image_format": "exr" + "image_format": "exr", + "default_frame": 0 } }, "publish": { diff --git a/openpype/settings/defaults/system_settings/modules.json b/openpype/settings/defaults/system_settings/modules.json index bb943524f1..22daae3b34 100644 --- a/openpype/settings/defaults/system_settings/modules.json +++ b/openpype/settings/defaults/system_settings/modules.json @@ -164,23 +164,6 @@ "default": "http://127.0.0.1:8082" } }, - "muster": { - "enabled": false, - "MUSTER_REST_URL": "http://127.0.0.1:9890", - "templates_mapping": { - "file_layers": 7, - "mentalray": 2, - "mentalray_sf": 6, - "redshift": 55, - "renderman": 29, - "software": 1, - "software_sf": 5, - "turtle": 10, - "vector": 4, - "vray": 37, - "ffmpeg": 48 - } - }, "royalrender": { "enabled": false, "rr_paths": { diff --git a/openpype/settings/entities/schemas/README.md b/openpype/settings/entities/schemas/README.md index c333628b25..eb74dd7a9c 100644 --- a/openpype/settings/entities/schemas/README.md +++ b/openpype/settings/entities/schemas/README.md @@ -645,7 +645,7 @@ How output of the schema could look like on save: }, "is_group": true, "key": "templates_mapping", - "label": "Muster - Templates mapping", + "label": "Deadline - Templates mapping", "is_file": true } ``` @@ -657,7 +657,7 @@ How output of the schema could look like on save: "object_type": "text", "is_group": true, "key": "templates_mapping", - "label": "Muster - Templates mapping", + "label": "Deadline - Templates mapping", "is_file": true } ``` diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json b/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json index 1aea778e32..42dea33ef9 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json @@ -362,6 +362,16 @@ "key": "use_gpu", "label": "Use GPU" }, + { + "type": "boolean", + "key": "workfile_dependency", + "label": "Workfile Dependency" + }, + { + "type": "boolean", + "key": "use_published_workfile", + "label": "Use Published Workfile" + }, { "type": "list", "key": "env_allowed_keys", diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_fusion.json b/openpype/settings/entities/schemas/projects_schema/schema_project_fusion.json index 8669842087..84d1efae78 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_fusion.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_fusion.json @@ -116,6 +116,17 @@ {"tif": "tif"}, {"jpg": "jpg"} ] + }, + { + "key": "default_frame_range_option", + "label": "Default frame range source", + "type": "enum", + "multiselect": false, + "enum_items": [ + {"asset_db": "Current asset context"}, + {"render_range": "From render in/out"}, + {"comp_range": "From composition timeline"} + ] } ] }, @@ -165,6 +176,11 @@ {"tif": "tif"}, {"jpg": "jpg"} ] + }, + { + "type": "number", + "key": "default_frame", + "label": "Default rendered frame" } ] } diff --git a/openpype/settings/entities/schemas/system_schema/schema_modules.json b/openpype/settings/entities/schemas/system_schema/schema_modules.json index 5b189eae88..88ef6f7515 100644 --- a/openpype/settings/entities/schemas/system_schema/schema_modules.json +++ b/openpype/settings/entities/schemas/system_schema/schema_modules.json @@ -207,37 +207,6 @@ } ] }, - { - "type": "dict", - "key": "muster", - "label": "Muster", - "require_restart": true, - "collapsible": true, - "checkbox_key": "enabled", - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "text", - "key": "MUSTER_REST_URL", - "label": "Muster Rest URL" - }, - { - "type": "dict-modifiable", - "object_type": { - "type": "number", - "minimum": 0, - "maximum": 300 - }, - "is_group": true, - "key": "templates_mapping", - "label": "Templates mapping" - } - ] - }, { "type": "dict", "key": "royalrender", diff --git a/openpype/tools/publisher/control.py b/openpype/tools/publisher/control.py index b02d83e4f6..47e374edf2 100644 --- a/openpype/tools/publisher/control.py +++ b/openpype/tools/publisher/control.py @@ -10,6 +10,7 @@ import inspect from abc import ABCMeta, abstractmethod import six +import arrow import pyblish.api from openpype import AYON_SERVER_ENABLED @@ -285,6 +286,8 @@ class PublishReportMaker: def get_report(self, publish_plugins=None): """Report data with all details of current state.""" + + now = arrow.utcnow().to("local") instances_details = {} for instance in self._all_instances_by_id.values(): instances_details[instance.id] = self._extract_instance_data( @@ -334,7 +337,8 @@ class PublishReportMaker: "context": self._extract_context_data(self._current_context), "crashed_file_paths": crashed_file_paths, "id": uuid.uuid4().hex, - "report_version": "1.0.0" + "created_at": now.isoformat(), + "report_version": "1.0.1", } def _extract_context_data(self, context): diff --git a/openpype/tools/publisher/publish_report_viewer/model.py b/openpype/tools/publisher/publish_report_viewer/model.py index 663a67ac70..460a269f1a 100644 --- a/openpype/tools/publisher/publish_report_viewer/model.py +++ b/openpype/tools/publisher/publish_report_viewer/model.py @@ -26,14 +26,14 @@ class InstancesModel(QtGui.QStandardItemModel): return self._items_by_id def set_report(self, report_item): - self.clear() + root_item = self.invisibleRootItem() + if root_item.rowCount() > 0: + root_item.removeRows(0, root_item.rowCount()) self._items_by_id.clear() self._plugin_items_by_id.clear() if not report_item: return - root_item = self.invisibleRootItem() - families = set(report_item.instance_items_by_family.keys()) families.remove(None) all_families = list(sorted(families)) @@ -125,14 +125,14 @@ class PluginsModel(QtGui.QStandardItemModel): return self._items_by_id def set_report(self, report_item): - self.clear() + root_item = self.invisibleRootItem() + if root_item.rowCount() > 0: + root_item.removeRows(0, root_item.rowCount()) self._items_by_id.clear() self._plugin_items_by_id.clear() if not report_item: return - root_item = self.invisibleRootItem() - labels_iter = iter(self.order_label_mapping) cur_order, cur_label = next(labels_iter) cur_plugin_items = [] diff --git a/openpype/tools/publisher/publish_report_viewer/window.py b/openpype/tools/publisher/publish_report_viewer/window.py index dc4ad70934..f9c8c05802 100644 --- a/openpype/tools/publisher/publish_report_viewer/window.py +++ b/openpype/tools/publisher/publish_report_viewer/window.py @@ -4,6 +4,7 @@ import six import uuid import appdirs +import arrow from qtpy import QtWidgets, QtCore, QtGui from openpype import style @@ -25,6 +26,7 @@ else: ITEM_ID_ROLE = QtCore.Qt.UserRole + 1 +ITEM_CREATED_AT_ROLE = QtCore.Qt.UserRole + 2 def get_reports_dir(): @@ -47,47 +49,77 @@ class PublishReportItem: """Report item representing one file in report directory.""" def __init__(self, content): - item_id = content.get("id") - changed = False - if not item_id: - item_id = str(uuid.uuid4()) - changed = True - content["id"] = item_id + changed = self._fix_content(content) - if not content.get("report_version"): - changed = True - content["report_version"] = "0.0.1" - - report_path = os.path.join(get_reports_dir(), item_id) + report_path = os.path.join(get_reports_dir(), content["id"]) file_modified = None if os.path.exists(report_path): file_modified = os.path.getmtime(report_path) + + created_at_obj = arrow.get(content["created_at"]).to("local") + created_at = created_at_obj.float_timestamp + self.content = content self.report_path = report_path self.file_modified = file_modified + self.created_at = float(created_at) self._loaded_label = content.get("label") self._changed = changed self.publish_report = PublishReport(content) @property def version(self): + """Publish report version. + + Returns: + str: Publish report version. + """ return self.content["report_version"] @property def id(self): + """Publish report id. + + Returns: + str: Publish report id. + """ + return self.content["id"] def get_label(self): + """Publish report label. + + Returns: + str: Publish report label showed in UI. + """ + return self.content.get("label") or "Unfilled label" def set_label(self, label): + """Set publish report label. + + Args: + label (str): New publish report label. + """ + if not label: self.content.pop("label", None) self.content["label"] = label label = property(get_label, set_label) + @property + def loaded_label(self): + return self._loaded_label + + def mark_as_changed(self): + """Mark report as changed.""" + + self._changed = True + def save(self): + """Save publish report to file.""" + save = False if ( self._changed @@ -109,6 +141,15 @@ class PublishReportItem: @classmethod def from_filepath(cls, filepath): + """Create report item from file. + + Args: + filepath (str): Path to report file. Content must be json. + + Returns: + PublishReportItem: Report item. + """ + if not os.path.exists(filepath): return None @@ -116,15 +157,25 @@ class PublishReportItem: with open(filepath, "r") as stream: content = json.load(stream) - return cls(content) + file_modified = os.path.getmtime(filepath) + changed = cls._fix_content(content, file_modified=file_modified) + obj = cls(content) + if changed: + obj.mark_as_changed() + return obj + except Exception: return None def remove_file(self): + """Remove report file.""" + if os.path.exists(self.report_path): os.remove(self.report_path) def update_file_content(self): + """Update report content in file.""" + if not os.path.exists(self.report_path): return @@ -148,9 +199,57 @@ class PublishReportItem: self.content = content self.file_modified = file_modified + @classmethod + def _fix_content(cls, content, file_modified=None): + """Fix content for backward compatibility of older report items. + + Args: + content (dict[str, Any]): Report content. + file_modified (Optional[float]): File modification time. + + Returns: + bool: True if content was changed, False otherwise. + """ + + # Fix created_at key + changed = cls._fix_created_at(content, file_modified) + + # NOTE backward compatibility for 'id' and 'report_version' is from + # 28.10.2022 https://github.com/ynput/OpenPype/pull/4040 + # We can probably safely remove it + + # Fix missing 'id' + item_id = content.get("id") + if not item_id: + item_id = str(uuid.uuid4()) + changed = True + content["id"] = item_id + + # Fix missing 'report_version' + if not content.get("report_version"): + changed = True + content["report_version"] = "0.0.1" + return changed + + @classmethod + def _fix_created_at(cls, content, file_modified): + # Key 'create_at' was added in report version 1.0.1 + created_at = content.get("created_at") + if created_at: + return False + + # Auto fix 'created_at', use file modification time if it is not set + # or current time if modification could not be received. + if file_modified is not None: + created_at_obj = arrow.Arrow.fromtimestamp(file_modified) + else: + created_at_obj = arrow.utcnow() + content["created_at"] = created_at_obj.to("local").isoformat() + return True + class PublisherReportHandler: - """Class handling storing publish report tool.""" + """Class handling storing publish report items.""" def __init__(self): self._reports = None @@ -173,14 +272,23 @@ class PublisherReportHandler: continue filepath = os.path.join(report_dir, filename) item = PublishReportItem.from_filepath(filepath) - reports.append(item) - reports_by_id[item.id] = item + if item is not None: + reports.append(item) + reports_by_id[item.id] = item self._reports = reports self._reports_by_id = reports_by_id return reports - def remove_report_items(self, item_id): + def remove_report_item(self, item_id): + """Remove report item by id. + + Remove from cache and also remove the file with the content. + + Args: + item_id (str): Report item id. + """ + item = self._reports_by_id.get(item_id) if item: try: @@ -191,9 +299,16 @@ class PublisherReportHandler: class LoadedFilesModel(QtGui.QStandardItemModel): + header_labels = ("Reports", "Created") + def __init__(self, *args, **kwargs): super(LoadedFilesModel, self).__init__(*args, **kwargs) + # Column count must be set before setting header data + self.setColumnCount(len(self.header_labels)) + for col, label in enumerate(self.header_labels): + self.setHeaderData(col, QtCore.Qt.Horizontal, label) + self._items_by_id = {} self._report_items_by_id = {} @@ -202,10 +317,14 @@ class LoadedFilesModel(QtGui.QStandardItemModel): self._loading_registry = False def refresh(self): - self._handler.reset() + root_item = self.invisibleRootItem() + if root_item.rowCount() > 0: + root_item.removeRows(0, root_item.rowCount()) self._items_by_id = {} self._report_items_by_id = {} + self._handler.reset() + new_items = [] for report_item in self._handler.list_reports(): item = self._create_item(report_item) @@ -217,26 +336,26 @@ class LoadedFilesModel(QtGui.QStandardItemModel): root_item = self.invisibleRootItem() root_item.appendRows(new_items) - def headerData(self, section, orientation, role): - if role in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole): - if section == 0: - return "Exports" - if section == 1: - return "Modified" - return "" - super(LoadedFilesModel, self).headerData(section, orientation, role) - def data(self, index, role=None): if role is None: role = QtCore.Qt.DisplayRole col = index.column() + if col == 1: + if role in ( + QtCore.Qt.DisplayRole, QtCore.Qt.InitialSortOrderRole + ): + role = ITEM_CREATED_AT_ROLE + if col != 0: index = self.index(index.row(), 0, index.parent()) return super(LoadedFilesModel, self).data(index, role) - def setData(self, index, value, role): + def setData(self, index, value, role=None): + if role is None: + role = QtCore.Qt.EditRole + if role == QtCore.Qt.EditRole: item_id = index.data(ITEM_ID_ROLE) report_item = self._report_items_by_id.get(item_id) @@ -247,6 +366,12 @@ class LoadedFilesModel(QtGui.QStandardItemModel): return super(LoadedFilesModel, self).setData(index, value, role) + def flags(self, index): + # Allow editable flag only for first column + if index.column() > 0: + return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled + return super(LoadedFilesModel, self).flags(index) + def _create_item(self, report_item): if report_item.id in self._items_by_id: return None @@ -254,6 +379,7 @@ class LoadedFilesModel(QtGui.QStandardItemModel): item = QtGui.QStandardItem(report_item.label) item.setColumnCount(self.columnCount()) item.setData(report_item.id, ITEM_ID_ROLE) + item.setData(report_item.created_at, ITEM_CREATED_AT_ROLE) return item @@ -278,16 +404,16 @@ class LoadedFilesModel(QtGui.QStandardItemModel): new_items = [] for normalized_path in filtered_paths: - try: - with open(normalized_path, "r") as stream: - data = json.load(stream) - report_item = PublishReportItem(data) - except Exception: - # TODO handle errors + report_item = PublishReportItem.from_filepath(normalized_path) + if report_item is None: continue - label = data.get("label") - if not label: + # Skip already added report items + # QUESTION: Should we replace existing or skip the item? + if report_item.id in self._items_by_id: + continue + + if not report_item.loaded_label: report_item.label = ( os.path.splitext(os.path.basename(filepath))[0] ) @@ -306,15 +432,13 @@ class LoadedFilesModel(QtGui.QStandardItemModel): root_item.appendRows(new_items) def remove_item_by_id(self, item_id): - report_item = self._report_items_by_id.get(item_id) - if not report_item: - return + self._handler.remove_report_item(item_id) - self._handler.remove_report_items(item_id) - item = self._items_by_id.get(item_id) - - parent = self.invisibleRootItem() - parent.removeRow(item.row()) + self._report_items_by_id.pop(item_id, None) + item = self._items_by_id.pop(item_id, None) + if item is not None: + parent = self.invisibleRootItem() + parent.removeRow(item.row()) def get_report_by_id(self, item_id): report_item = self._report_items_by_id.get(item_id) @@ -335,13 +459,18 @@ class LoadedFilesView(QtWidgets.QTreeView): ) self.setIndentation(0) self.setAlternatingRowColors(True) + self.setSortingEnabled(True) model = LoadedFilesModel() - self.setModel(model) + proxy_model = QtCore.QSortFilterProxyModel() + proxy_model.setSourceModel(model) + self.setModel(proxy_model) time_delegate = PrettyTimeDelegate() self.setItemDelegateForColumn(1, time_delegate) + self.sortByColumn(1, QtCore.Qt.AscendingOrder) + remove_btn = IconButton(self) remove_icon_path = resources.get_icon_path("delete") loaded_remove_image = QtGui.QImage(remove_icon_path) @@ -356,6 +485,7 @@ class LoadedFilesView(QtWidgets.QTreeView): ) self._model = model + self._proxy_model = proxy_model self._time_delegate = time_delegate self._remove_btn = remove_btn @@ -403,7 +533,8 @@ class LoadedFilesView(QtWidgets.QTreeView): if index.isValid(): return - index = self._model.index(0, 0) + model = self.model() + index = model.index(0, 0) if index.isValid(): self.setCurrentIndex(index) diff --git a/openpype/tools/settings/settings/README.md b/openpype/tools/settings/settings/README.md index c29664a907..8f4ec00a76 100644 --- a/openpype/tools/settings/settings/README.md +++ b/openpype/tools/settings/settings/README.md @@ -334,7 +334,7 @@ }, "is_group": true, "key": "templates_mapping", - "label": "Muster - Templates mapping", + "label": "Deadline - Templates mapping", "is_file": true } ``` @@ -346,7 +346,7 @@ "object_type": "text", "is_group": true, "key": "templates_mapping", - "label": "Muster - Templates mapping", + "label": "Deadline - Templates mapping", "is_file": true } ``` diff --git a/openpype/tools/utils/lib.py b/openpype/tools/utils/lib.py index 723e71e7aa..365caaafd9 100644 --- a/openpype/tools/utils/lib.py +++ b/openpype/tools/utils/lib.py @@ -91,7 +91,8 @@ def set_style_property(widget, property_name, property_value): if cur_value == property_value: return widget.setProperty(property_name, property_value) - widget.style().polish(widget) + style = widget.style() + style.polish(widget) def paint_image_with_color(image, color): diff --git a/openpype/version.py b/openpype/version.py index 5981cb657a..2f2fc517b8 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.18.4-nightly.1" +__version__ = "3.18.6-nightly.1" diff --git a/pyproject.toml b/pyproject.toml index bad481c889..24172aa77f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.18.3" # OpenPype +version = "3.18.5" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" diff --git a/server_addon/aftereffects/server/settings/creator_plugins.py b/server_addon/aftereffects/server/settings/creator_plugins.py index 9cb03b0b26..988a036589 100644 --- a/server_addon/aftereffects/server/settings/creator_plugins.py +++ b/server_addon/aftereffects/server/settings/creator_plugins.py @@ -1,18 +1,16 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class CreateRenderPlugin(BaseSettingsModel): - mark_for_review: bool = Field(True, title="Review") - default_variants: list[str] = Field( + mark_for_review: bool = SettingsField(True, title="Review") + default_variants: list[str] = SettingsField( default_factory=list, title="Default Variants" ) class AfterEffectsCreatorPlugins(BaseSettingsModel): - RenderCreator: CreateRenderPlugin = Field( + RenderCreator: CreateRenderPlugin = SettingsField( title="Create Render", default_factory=CreateRenderPlugin, ) diff --git a/server_addon/aftereffects/server/settings/imageio.py b/server_addon/aftereffects/server/settings/imageio.py index 55160ffd11..4657425c81 100644 --- a/server_addon/aftereffects/server/settings/imageio.py +++ b/server_addon/aftereffects/server/settings/imageio.py @@ -1,29 +1,29 @@ -from pydantic import Field, validator -from ayon_server.settings import BaseSettingsModel +from pydantic import validator +from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.settings.validators import ensure_unique_names class ImageIOConfigModel(BaseSettingsModel): - override_global_config: bool = Field( + override_global_config: bool = SettingsField( False, title="Override global OCIO config" ) - filepath: list[str] = Field( + filepath: list[str] = SettingsField( default_factory=list, title="Config path" ) class ImageIOFileRuleModel(BaseSettingsModel): - name: str = Field("", title="Rule name") - pattern: str = Field("", title="Regex pattern") - colorspace: str = Field("", title="Colorspace name") - ext: str = Field("", title="File extension") + name: str = SettingsField("", title="Rule name") + pattern: str = SettingsField("", title="Regex pattern") + colorspace: str = SettingsField("", title="Colorspace name") + ext: str = SettingsField("", title="File extension") class ImageIOFileRulesModel(BaseSettingsModel): - activate_host_rules: bool = Field(False) - rules: list[ImageIOFileRuleModel] = Field( + activate_host_rules: bool = SettingsField(False) + rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, title="Rules" ) @@ -35,14 +35,14 @@ class ImageIOFileRulesModel(BaseSettingsModel): class AfterEffectsImageIOModel(BaseSettingsModel): - activate_host_color_management: bool = Field( + activate_host_color_management: bool = SettingsField( True, title="Enable Color Management" ) - ocio_config: ImageIOConfigModel = Field( + ocio_config: ImageIOConfigModel = SettingsField( default_factory=ImageIOConfigModel, title="OCIO config" ) - file_rules: ImageIOFileRulesModel = Field( + file_rules: ImageIOFileRulesModel = SettingsField( default_factory=ImageIOFileRulesModel, title="File Rules" ) diff --git a/server_addon/aftereffects/server/settings/main.py b/server_addon/aftereffects/server/settings/main.py index 4edc46d259..f30f4dc258 100644 --- a/server_addon/aftereffects/server/settings/main.py +++ b/server_addon/aftereffects/server/settings/main.py @@ -1,5 +1,4 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField from .imageio import AfterEffectsImageIOModel from .creator_plugins import AfterEffectsCreatorPlugins @@ -14,23 +13,23 @@ from .templated_workfile_build import TemplatedWorkfileBuildModel class AfterEffectsSettings(BaseSettingsModel): """AfterEffects Project Settings.""" - imageio: AfterEffectsImageIOModel = Field( + imageio: AfterEffectsImageIOModel = SettingsField( default_factory=AfterEffectsImageIOModel, title="OCIO config" ) - create: AfterEffectsCreatorPlugins = Field( + create: AfterEffectsCreatorPlugins = SettingsField( default_factory=AfterEffectsCreatorPlugins, title="Creator plugins" ) - publish: AfterEffectsPublishPlugins = Field( + publish: AfterEffectsPublishPlugins = SettingsField( default_factory=AfterEffectsPublishPlugins, title="Publish plugins" ) - workfile_builder: WorkfileBuilderPlugin = Field( + workfile_builder: WorkfileBuilderPlugin = SettingsField( default_factory=WorkfileBuilderPlugin, title="Workfile Builder" ) - templated_workfile_build: TemplatedWorkfileBuildModel = Field( + templated_workfile_build: TemplatedWorkfileBuildModel = SettingsField( default_factory=TemplatedWorkfileBuildModel, title="Templated Workfile Build Settings" ) diff --git a/server_addon/aftereffects/server/settings/publish_plugins.py b/server_addon/aftereffects/server/settings/publish_plugins.py index 78445d3223..61d67f26d3 100644 --- a/server_addon/aftereffects/server/settings/publish_plugins.py +++ b/server_addon/aftereffects/server/settings/publish_plugins.py @@ -1,45 +1,43 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class CollectReviewPluginModel(BaseSettingsModel): - enabled: bool = Field(True, title="Enabled") + enabled: bool = SettingsField(True, title="Enabled") class ValidateSceneSettingsModel(BaseSettingsModel): """Validate naming of products and layers""" # _isGroup = True - enabled: bool = Field(True, title="Enabled") - optional: bool = Field(False, title="Optional") - active: bool = Field(True, title="Active") - skip_resolution_check: list[str] = Field( + enabled: bool = SettingsField(True, title="Enabled") + optional: bool = SettingsField(False, title="Optional") + active: bool = SettingsField(True, title="Active") + skip_resolution_check: list[str] = SettingsField( default_factory=list, title="Skip Resolution Check for Tasks", ) - skip_timelines_check: list[str] = Field( + skip_timelines_check: list[str] = SettingsField( default_factory=list, title="Skip Timeline Check for Tasks", ) class ValidateContainersModel(BaseSettingsModel): - enabled: bool = Field(True, title="Enabled") - optional: bool = Field(True, title="Optional") - active: bool = Field(True, title="Active") + enabled: bool = SettingsField(True, title="Enabled") + optional: bool = SettingsField(True, title="Optional") + active: bool = SettingsField(True, title="Active") class AfterEffectsPublishPlugins(BaseSettingsModel): - CollectReview: CollectReviewPluginModel = Field( + CollectReview: CollectReviewPluginModel = SettingsField( default_factory=CollectReviewPluginModel, title="Collect Review", ) - ValidateSceneSettings: ValidateSceneSettingsModel = Field( + ValidateSceneSettings: ValidateSceneSettingsModel = SettingsField( default_factory=ValidateSceneSettingsModel, title="Validate Scene Settings", ) - ValidateContainers: ValidateContainersModel = Field( + ValidateContainers: ValidateContainersModel = SettingsField( default_factory=ValidateContainersModel, title="Validate Containers", ) diff --git a/server_addon/aftereffects/server/settings/templated_workfile_build.py b/server_addon/aftereffects/server/settings/templated_workfile_build.py index e0245c8d06..5b71c2addc 100644 --- a/server_addon/aftereffects/server/settings/templated_workfile_build.py +++ b/server_addon/aftereffects/server/settings/templated_workfile_build.py @@ -1,33 +1,33 @@ -from pydantic import Field from ayon_server.settings import ( BaseSettingsModel, task_types_enum, + SettingsField, ) class TemplatedWorkfileProfileModel(BaseSettingsModel): - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - task_names: list[str] = Field( + task_names: list[str] = SettingsField( default_factory=list, title="Task names" ) - path: str = Field( + path: str = SettingsField( title="Path to template" ) - keep_placeholder: bool = Field( + keep_placeholder: bool = SettingsField( False, title="Keep placeholders") - create_first_version: bool = Field( + create_first_version: bool = SettingsField( True, title="Create first version" ) class TemplatedWorkfileBuildModel(BaseSettingsModel): - profiles: list[TemplatedWorkfileProfileModel] = Field( + profiles: list[TemplatedWorkfileProfileModel] = SettingsField( default_factory=list ) diff --git a/server_addon/aftereffects/server/settings/workfile_builder.py b/server_addon/aftereffects/server/settings/workfile_builder.py index d45d3f7f24..65f5ddd893 100644 --- a/server_addon/aftereffects/server/settings/workfile_builder.py +++ b/server_addon/aftereffects/server/settings/workfile_builder.py @@ -1,25 +1,27 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel, MultiplatformPathModel +from ayon_server.settings import ( + BaseSettingsModel, + SettingsField, + MultiplatformPathModel, +) class CustomBuilderTemplate(BaseSettingsModel): - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, title="Task types", ) - template_path: MultiplatformPathModel = Field( + template_path: MultiplatformPathModel = SettingsField( default_factory=MultiplatformPathModel ) class WorkfileBuilderPlugin(BaseSettingsModel): _title = "Workfile Builder" - create_first_version: bool = Field( + create_first_version: bool = SettingsField( False, title="Create first workfile" ) - custom_templates: list[CustomBuilderTemplate] = Field( + custom_templates: list[CustomBuilderTemplate] = SettingsField( default_factory=list ) diff --git a/server_addon/applications/server/applications.json b/server_addon/applications/server/applications.json index 35f1b4cfbb..b0b12b2003 100644 --- a/server_addon/applications/server/applications.json +++ b/server_addon/applications/server/applications.json @@ -307,9 +307,9 @@ ] }, "arguments": { - "windows": [], + "windows": ["--nukeassist"], "darwin": [], - "linux": [] + "linux": ["--nukeassist"] }, "environment": "{}", "use_python_2": false @@ -329,9 +329,9 @@ ] }, "arguments": { - "windows": [], + "windows": ["--nukeassist"], "darwin": [], - "linux": [] + "linux": ["--nukeassist"] }, "environment": "{}", "use_python_2": false @@ -351,9 +351,9 @@ ] }, "arguments": { - "windows": [], + "windows": ["--nukeassist"], "darwin": [], - "linux": [] + "linux": ["--nukeassist"] }, "environment": "{}", "use_python_2": false @@ -382,9 +382,9 @@ ] }, "arguments": { - "windows": [], + "windows": ["--nukex"], "darwin": [], - "linux": [] + "linux": ["--nukex"] }, "environment": "{}", "use_python_2": false @@ -404,9 +404,9 @@ ] }, "arguments": { - "windows": [], + "windows": ["--nukex"], "darwin": [], - "linux": [] + "linux": ["--nukex"] }, "environment": "{}", "use_python_2": false @@ -426,9 +426,9 @@ ] }, "arguments": { - "windows": [], + "windows": ["--nukex"], "darwin": [], - "linux": [] + "linux": ["--nukex"] }, "environment": "{}", "use_python_2": false @@ -457,9 +457,9 @@ ] }, "arguments": { - "windows": [], + "windows": ["--studio"], "darwin": [], - "linux": [] + "linux": ["--studio"] }, "environment": "{}", "use_python_2": false @@ -479,9 +479,9 @@ ] }, "arguments": { - "windows": [], + "windows": ["--studio"], "darwin": [], - "linux": [] + "linux": ["--studio"] }, "environment": "{}", "use_python_2": false @@ -501,9 +501,9 @@ ] }, "arguments": { - "windows": [], + "windows": ["--studio"], "darwin": [], - "linux": [] + "linux": ["--studio"] }, "environment": "{}", "use_python_2": false @@ -532,9 +532,9 @@ ] }, "arguments": { - "windows": [], + "windows": ["--hiero"], "darwin": [], - "linux": [] + "linux": ["--hiero"] }, "environment": "{}", "use_python_2": false @@ -554,9 +554,9 @@ ] }, "arguments": { - "windows": [], + "windows": ["--hiero"], "darwin": [], - "linux": [] + "linux": ["--hiero"] }, "environment": "{}", "use_python_2": false @@ -576,9 +576,9 @@ ] }, "arguments": { - "windows": [], + "windows": ["--hiero"], "darwin": [], - "linux": [] + "linux": ["--hiero"] }, "environment": "{}", "use_python_2": false diff --git a/server_addon/applications/server/settings.py b/server_addon/applications/server/settings.py index 70c8b57c6a..e0a59604c8 100644 --- a/server_addon/applications/server/settings.py +++ b/server_addon/applications/server/settings.py @@ -1,7 +1,11 @@ import json -from pydantic import Field, validator +from pydantic import validator -from ayon_server.settings import BaseSettingsModel, ensure_unique_names +from ayon_server.settings import ( + BaseSettingsModel, + SettingsField, + ensure_unique_names, +) from ayon_server.exceptions import BadRequestException @@ -23,21 +27,23 @@ def validate_json_dict(value): class MultiplatformStrList(BaseSettingsModel): - windows: list[str] = Field(default_factory=list, title="Windows") - linux: list[str] = Field(default_factory=list, title="Linux") - darwin: list[str] = Field(default_factory=list, title="MacOS") + windows: list[str] = SettingsField(default_factory=list, title="Windows") + linux: list[str] = SettingsField(default_factory=list, title="Linux") + darwin: list[str] = SettingsField(default_factory=list, title="MacOS") class AppVariant(BaseSettingsModel): - name: str = Field("", title="Name") - label: str = Field("", title="Label") - executables: MultiplatformStrList = Field( + name: str = SettingsField("", title="Name") + label: str = SettingsField("", title="Label") + executables: MultiplatformStrList = SettingsField( default_factory=MultiplatformStrList, title="Executables" ) - arguments: MultiplatformStrList = Field( + arguments: MultiplatformStrList = SettingsField( default_factory=MultiplatformStrList, title="Arguments" ) - environment: str = Field("{}", title="Environment", widget="textarea") + environment: str = SettingsField( + "{}", title="Environment", widget="textarea" + ) @validator("environment") def validate_json(cls, value): @@ -45,17 +51,19 @@ class AppVariant(BaseSettingsModel): class AppVariantWithPython(AppVariant): - use_python_2: bool = Field(False, title="Use Python 2") + use_python_2: bool = SettingsField(False, title="Use Python 2") class AppGroup(BaseSettingsModel): - enabled: bool = Field(True) - label: str = Field("", title="Label") - host_name: str = Field("", title="Host name") - icon: str = Field("", title="Icon") - environment: str = Field("{}", title="Environment", widget="textarea") + enabled: bool = SettingsField(True) + label: str = SettingsField("", title="Label") + host_name: str = SettingsField("", title="Host name") + icon: str = SettingsField("", title="Icon") + environment: str = SettingsField( + "{}", title="Environment", widget="textarea" + ) - variants: list[AppVariant] = Field( + variants: list[AppVariant] = SettingsField( default_factory=list, title="Variants", description="Different variants of the applications", @@ -69,7 +77,7 @@ class AppGroup(BaseSettingsModel): class AppGroupWithPython(AppGroup): - variants: list[AppVariantWithPython] = Field( + variants: list[AppVariantWithPython] = SettingsField( default_factory=list, title="Variants", description="Different variants of the applications", @@ -78,14 +86,16 @@ class AppGroupWithPython(AppGroup): class AdditionalAppGroup(BaseSettingsModel): - enabled: bool = Field(True) - name: str = Field("", title="Name") - label: str = Field("", title="Label") - host_name: str = Field("", title="Host name") - icon: str = Field("", title="Icon") - environment: str = Field("{}", title="Environment", widget="textarea") + enabled: bool = SettingsField(True) + name: str = SettingsField("", title="Name") + label: str = SettingsField("", title="Label") + host_name: str = SettingsField("", title="Host name") + icon: str = SettingsField("", title="Icon") + environment: str = SettingsField( + "{}", title="Environment", widget="textarea" + ) - variants: list[AppVariantWithPython] = Field( + variants: list[AppVariantWithPython] = SettingsField( default_factory=list, title="Variants", description="Different variants of the applications", @@ -99,12 +109,16 @@ class AdditionalAppGroup(BaseSettingsModel): class ToolVariantModel(BaseSettingsModel): - name: str = Field("", title="Name") - label: str = Field("", title="Label") - host_names: list[str] = Field(default_factory=list, title="Hosts") + name: str = SettingsField("", title="Name") + label: str = SettingsField("", title="Label") + host_names: list[str] = SettingsField(default_factory=list, title="Hosts") # TODO use applications enum if possible - app_variants: list[str] = Field(default_factory=list, title="Applications") - environment: str = Field("{}", title="Environments", widget="textarea") + app_variants: list[str] = SettingsField( + default_factory=list, title="Applications" + ) + environment: str = SettingsField( + "{}", title="Environments", widget="textarea" + ) @validator("environment") def validate_json(cls, value): @@ -112,10 +126,12 @@ class ToolVariantModel(BaseSettingsModel): class ToolGroupModel(BaseSettingsModel): - name: str = Field("", title="Name") - label: str = Field("", title="Label") - environment: str = Field("{}", title="Environments", widget="textarea") - variants: list[ToolVariantModel] = Field(default_factory=list) + name: str = SettingsField("", title="Name") + label: str = SettingsField("", title="Label") + environment: str = SettingsField( + "{}", title="Environments", widget="textarea" + ) + variants: list[ToolVariantModel] = SettingsField(default_factory=list) @validator("environment") def validate_json(cls, value): @@ -130,47 +146,47 @@ class ToolGroupModel(BaseSettingsModel): class ApplicationsSettings(BaseSettingsModel): """Applications settings""" - maya: AppGroupWithPython = Field( + maya: AppGroupWithPython = SettingsField( default_factory=AppGroupWithPython, title="Autodesk Maya") - adsk_3dsmax: AppGroupWithPython = Field( + adsk_3dsmax: AppGroupWithPython = SettingsField( default_factory=AppGroupWithPython, title="Autodesk 3ds Max") - flame: AppGroupWithPython = Field( + flame: AppGroupWithPython = SettingsField( default_factory=AppGroupWithPython, title="Autodesk Flame") - nuke: AppGroupWithPython = Field( + nuke: AppGroupWithPython = SettingsField( default_factory=AppGroupWithPython, title="Nuke") - nukeassist: AppGroupWithPython = Field( + nukeassist: AppGroupWithPython = SettingsField( default_factory=AppGroupWithPython, title="Nuke Assist") - nukex: AppGroupWithPython = Field( + nukex: AppGroupWithPython = SettingsField( default_factory=AppGroupWithPython, title="Nuke X") - nukestudio: AppGroupWithPython = Field( + nukestudio: AppGroupWithPython = SettingsField( default_factory=AppGroupWithPython, title="Nuke Studio") - hiero: AppGroupWithPython = Field( + hiero: AppGroupWithPython = SettingsField( default_factory=AppGroupWithPython, title="Hiero") - fusion: AppGroup = Field( + fusion: AppGroup = SettingsField( default_factory=AppGroupWithPython, title="Fusion") - resolve: AppGroupWithPython = Field( + resolve: AppGroupWithPython = SettingsField( default_factory=AppGroupWithPython, title="Resolve") - houdini: AppGroupWithPython = Field( + houdini: AppGroupWithPython = SettingsField( default_factory=AppGroupWithPython, title="Houdini") - blender: AppGroup = Field( + blender: AppGroup = SettingsField( default_factory=AppGroupWithPython, title="Blender") - harmony: AppGroup = Field( + harmony: AppGroup = SettingsField( default_factory=AppGroupWithPython, title="Harmony") - tvpaint: AppGroup = Field( + tvpaint: AppGroup = SettingsField( default_factory=AppGroupWithPython, title="TVPaint") - photoshop: AppGroup = Field( + photoshop: AppGroup = SettingsField( default_factory=AppGroupWithPython, title="Adobe Photoshop") - aftereffects: AppGroup = Field( + aftereffects: AppGroup = SettingsField( default_factory=AppGroupWithPython, title="Adobe After Effects") - celaction: AppGroup = Field( + celaction: AppGroup = SettingsField( default_factory=AppGroupWithPython, title="Celaction 2D") - substancepainter: AppGroup = Field( + substancepainter: AppGroup = SettingsField( default_factory=AppGroupWithPython, title="Substance Painter") - unreal: AppGroup = Field( + unreal: AppGroup = SettingsField( default_factory=AppGroupWithPython, title="Unreal Editor") - wrap: AppGroup = Field( + wrap: AppGroup = SettingsField( default_factory=AppGroupWithPython, title="Wrap") - additional_apps: list[AdditionalAppGroup] = Field( + additional_apps: list[AdditionalAppGroup] = SettingsField( default_factory=list, title="Additional Applications") @validator("additional_apps") @@ -180,16 +196,16 @@ class ApplicationsSettings(BaseSettingsModel): class ApplicationsAddonSettings(BaseSettingsModel): - applications: ApplicationsSettings = Field( + applications: ApplicationsSettings = SettingsField( default_factory=ApplicationsSettings, title="Applications", scope=["studio"] ) - tool_groups: list[ToolGroupModel] = Field( + tool_groups: list[ToolGroupModel] = SettingsField( default_factory=list, scope=["studio"] ) - only_available: bool = Field( + only_available: bool = SettingsField( True, title="Show only available applications") @validator("tool_groups") diff --git a/server_addon/applications/server/version.py b/server_addon/applications/server/version.py index ae7362549b..bbab0242f6 100644 --- a/server_addon/applications/server/version.py +++ b/server_addon/applications/server/version.py @@ -1 +1 @@ -__version__ = "0.1.3" +__version__ = "0.1.4" diff --git a/server_addon/blender/server/settings/imageio.py b/server_addon/blender/server/settings/imageio.py index a6d3c5ff64..412d01638f 100644 --- a/server_addon/blender/server/settings/imageio.py +++ b/server_addon/blender/server/settings/imageio.py @@ -1,29 +1,29 @@ -from pydantic import Field, validator -from ayon_server.settings import BaseSettingsModel +from pydantic import validator +from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.settings.validators import ensure_unique_names class ImageIOConfigModel(BaseSettingsModel): - override_global_config: bool = Field( + override_global_config: bool = SettingsField( False, title="Override global OCIO config" ) - filepath: list[str] = Field( + filepath: list[str] = SettingsField( default_factory=list, title="Config path" ) class ImageIOFileRuleModel(BaseSettingsModel): - name: str = Field("", title="Rule name") - pattern: str = Field("", title="Regex pattern") - colorspace: str = Field("", title="Colorspace name") - ext: str = Field("", title="File extension") + name: str = SettingsField("", title="Rule name") + pattern: str = SettingsField("", title="Regex pattern") + colorspace: str = SettingsField("", title="Colorspace name") + ext: str = SettingsField("", title="File extension") class ImageIOFileRulesModel(BaseSettingsModel): - activate_host_rules: bool = Field(False) - rules: list[ImageIOFileRuleModel] = Field( + activate_host_rules: bool = SettingsField(False) + rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, title="Rules" ) @@ -35,14 +35,14 @@ class ImageIOFileRulesModel(BaseSettingsModel): class BlenderImageIOModel(BaseSettingsModel): - activate_host_color_management: bool = Field( + activate_host_color_management: bool = SettingsField( True, title="Enable Color Management" ) - ocio_config: ImageIOConfigModel = Field( + ocio_config: ImageIOConfigModel = SettingsField( default_factory=ImageIOConfigModel, title="OCIO config" ) - file_rules: ImageIOFileRulesModel = Field( + file_rules: ImageIOFileRulesModel = SettingsField( default_factory=ImageIOFileRulesModel, title="File Rules" ) diff --git a/server_addon/blender/server/settings/main.py b/server_addon/blender/server/settings/main.py index 3d53162e45..aed9b5632d 100644 --- a/server_addon/blender/server/settings/main.py +++ b/server_addon/blender/server/settings/main.py @@ -1,6 +1,6 @@ -from pydantic import Field from ayon_server.settings import ( BaseSettingsModel, + SettingsField, TemplateWorkfileBaseOptions, ) @@ -16,38 +16,38 @@ from .render_settings import ( class UnitScaleSettingsModel(BaseSettingsModel): - enabled: bool = Field(True, title="Enabled") - apply_on_opening: bool = Field( + enabled: bool = SettingsField(True, title="Enabled") + apply_on_opening: bool = SettingsField( False, title="Apply on Opening Existing Files") - base_file_unit_scale: float = Field( + base_file_unit_scale: float = SettingsField( 1.0, title="Base File Unit Scale" ) class BlenderSettings(BaseSettingsModel): - unit_scale_settings: UnitScaleSettingsModel = Field( + unit_scale_settings: UnitScaleSettingsModel = SettingsField( default_factory=UnitScaleSettingsModel, title="Set Unit Scale" ) - set_resolution_startup: bool = Field( + set_resolution_startup: bool = SettingsField( True, title="Set Resolution on Startup" ) - set_frames_startup: bool = Field( + set_frames_startup: bool = SettingsField( True, title="Set Start/End Frames and FPS on Startup" ) - imageio: BlenderImageIOModel = Field( + imageio: BlenderImageIOModel = SettingsField( default_factory=BlenderImageIOModel, title="Color Management (ImageIO)" ) - RenderSettings: RenderSettingsModel = Field( + RenderSettings: RenderSettingsModel = SettingsField( default_factory=RenderSettingsModel, title="Render Settings") - workfile_builder: TemplateWorkfileBaseOptions = Field( + workfile_builder: TemplateWorkfileBaseOptions = SettingsField( default_factory=TemplateWorkfileBaseOptions, title="Workfile Builder" ) - publish: PublishPuginsModel = Field( + publish: PublishPuginsModel = SettingsField( default_factory=PublishPuginsModel, title="Publish Plugins" ) diff --git a/server_addon/blender/server/settings/publish_plugins.py b/server_addon/blender/server/settings/publish_plugins.py index 9a1e0c681e..c2a989dd55 100644 --- a/server_addon/blender/server/settings/publish_plugins.py +++ b/server_addon/blender/server/settings/publish_plugins.py @@ -1,7 +1,7 @@ import json -from pydantic import Field, validator +from pydantic import validator from ayon_server.exceptions import BadRequestException -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField def validate_json_dict(value): @@ -21,36 +21,36 @@ def validate_json_dict(value): class ValidatePluginModel(BaseSettingsModel): - enabled: bool = Field(True) - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") + enabled: bool = SettingsField(True) + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") class ValidateFileSavedModel(BaseSettingsModel): - enabled: bool = Field(title="ValidateFileSaved") - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") - exclude_families: list[str] = Field( + enabled: bool = SettingsField(title="ValidateFileSaved") + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") + exclude_families: list[str] = SettingsField( default_factory=list, title="Exclude product types" ) class ExtractBlendModel(BaseSettingsModel): - enabled: bool = Field(True) - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") - families: list[str] = Field( + enabled: bool = SettingsField(True) + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") + families: list[str] = SettingsField( default_factory=list, title="Families" ) class ExtractPlayblastModel(BaseSettingsModel): - enabled: bool = Field(True) - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") - presets: str = Field("", title="Presets", widget="textarea") + enabled: bool = SettingsField(True) + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") + presets: str = SettingsField("", title="Presets", widget="textarea") @validator("presets") def validate_json(cls, value): @@ -58,83 +58,83 @@ class ExtractPlayblastModel(BaseSettingsModel): class PublishPuginsModel(BaseSettingsModel): - ValidateCameraZeroKeyframe: ValidatePluginModel = Field( + ValidateCameraZeroKeyframe: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Validate Camera Zero Keyframe", section="General Validators" ) - ValidateFileSaved: ValidateFileSavedModel = Field( + ValidateFileSaved: ValidateFileSavedModel = SettingsField( default_factory=ValidateFileSavedModel, title="Validate File Saved", ) - ValidateInstanceEmpty: ValidatePluginModel = Field( + ValidateInstanceEmpty: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Validate Instance is not Empty" ) - ValidateMeshHasUvs: ValidatePluginModel = Field( + ValidateMeshHasUvs: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Validate Mesh Has Uvs", section="Model Validators" ) - ValidateMeshNoNegativeScale: ValidatePluginModel = Field( + ValidateMeshNoNegativeScale: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Validate Mesh No Negative Scale" ) - ValidateTransformZero: ValidatePluginModel = Field( + ValidateTransformZero: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Validate Transform Zero" ) - ValidateNoColonsInName: ValidatePluginModel = Field( + ValidateNoColonsInName: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Validate No Colons In Name" ) - ValidateRenderCameraIsSet: ValidatePluginModel = Field( + ValidateRenderCameraIsSet: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Validate Render Camera Is Set", section="Render Validators" ) - ValidateDeadlinePublish: ValidatePluginModel = Field( + ValidateDeadlinePublish: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Validate Render Output for Deadline", ) - ExtractBlend: ExtractBlendModel = Field( + ExtractBlend: ExtractBlendModel = SettingsField( default_factory=ExtractBlendModel, title="Extract Blend", section="Extractors" ) - ExtractFBX: ValidatePluginModel = Field( + ExtractFBX: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Extract FBX" ) - ExtractModelABC: ValidatePluginModel = Field( + ExtractModelABC: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Extract ABC" ) - ExtractBlendAnimation: ValidatePluginModel = Field( + ExtractBlendAnimation: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Extract Blend Animation" ) - ExtractAnimationFBX: ValidatePluginModel = Field( + ExtractAnimationFBX: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Extract Animation FBX" ) - ExtractCamera: ValidatePluginModel = Field( + ExtractCamera: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Extract Camera" ) - ExtractCameraABC: ValidatePluginModel = Field( + ExtractCameraABC: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Extract Camera as ABC" ) - ExtractLayout: ValidatePluginModel = Field( + ExtractLayout: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Extract Layout (JSON)" ) - ExtractThumbnail: ExtractPlayblastModel = Field( + ExtractThumbnail: ExtractPlayblastModel = SettingsField( default_factory=ExtractPlayblastModel, title="Extract Thumbnail" ) - ExtractPlayblast: ExtractPlayblastModel = Field( + ExtractPlayblast: ExtractPlayblastModel = SettingsField( default_factory=ExtractPlayblastModel, title="Extract Playblast" ) diff --git a/server_addon/blender/server/settings/render_settings.py b/server_addon/blender/server/settings/render_settings.py index f62013982e..f91ba1627a 100644 --- a/server_addon/blender/server/settings/render_settings.py +++ b/server_addon/blender/server/settings/render_settings.py @@ -1,7 +1,5 @@ """Providing models and values for Blender Render Settings.""" -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField def aov_separators_enum(): @@ -58,8 +56,8 @@ class CustomPassesModel(BaseSettingsModel): """Custom Passes""" _layout = "compact" - attribute: str = Field("", title="Attribute name") - value: str = Field( + attribute: str = SettingsField("", title="Attribute name") + value: str = SettingsField( "COLOR", title="Type", enum_resolver=custom_passes_types_enum @@ -67,28 +65,28 @@ class CustomPassesModel(BaseSettingsModel): class RenderSettingsModel(BaseSettingsModel): - default_render_image_folder: str = Field( + default_render_image_folder: str = SettingsField( title="Default Render Image Folder" ) - aov_separator: str = Field( + aov_separator: str = SettingsField( "underscore", title="AOV Separator Character", enum_resolver=aov_separators_enum ) - image_format: str = Field( + image_format: str = SettingsField( "exr", title="Image Format", enum_resolver=image_format_enum ) - multilayer_exr: bool = Field( + multilayer_exr: bool = SettingsField( title="Multilayer (EXR)" ) - aov_list: list[str] = Field( + aov_list: list[str] = SettingsField( default_factory=list, enum_resolver=aov_list_enum, title="AOVs to create" ) - custom_passes: list[CustomPassesModel] = Field( + custom_passes: list[CustomPassesModel] = SettingsField( default_factory=list, title="Custom Passes", description=( diff --git a/server_addon/celaction/server/imageio.py b/server_addon/celaction/server/imageio.py index 72da441528..1e1ac6ff52 100644 --- a/server_addon/celaction/server/imageio.py +++ b/server_addon/celaction/server/imageio.py @@ -1,29 +1,29 @@ -from pydantic import Field, validator -from ayon_server.settings import BaseSettingsModel +from pydantic import validator +from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.settings.validators import ensure_unique_names class ImageIOConfigModel(BaseSettingsModel): - override_global_config: bool = Field( + override_global_config: bool = SettingsField( False, title="Override global OCIO config" ) - filepath: list[str] = Field( + filepath: list[str] = SettingsField( default_factory=list, title="Config path" ) class ImageIOFileRuleModel(BaseSettingsModel): - name: str = Field("", title="Rule name") - pattern: str = Field("", title="Regex pattern") - colorspace: str = Field("", title="Colorspace name") - ext: str = Field("", title="File extension") + name: str = SettingsField("", title="Rule name") + pattern: str = SettingsField("", title="Regex pattern") + colorspace: str = SettingsField("", title="Colorspace name") + ext: str = SettingsField("", title="File extension") class ImageIOFileRulesModel(BaseSettingsModel): - activate_host_rules: bool = Field(False) - rules: list[ImageIOFileRuleModel] = Field( + activate_host_rules: bool = SettingsField(False) + rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, title="Rules" ) @@ -35,14 +35,14 @@ class ImageIOFileRulesModel(BaseSettingsModel): class CelActionImageIOModel(BaseSettingsModel): - activate_host_color_management: bool = Field( + activate_host_color_management: bool = SettingsField( True, title="Enable Color Management" ) - ocio_config: ImageIOConfigModel = Field( + ocio_config: ImageIOConfigModel = SettingsField( default_factory=ImageIOConfigModel, title="OCIO config" ) - file_rules: ImageIOFileRulesModel = Field( + file_rules: ImageIOFileRulesModel = SettingsField( default_factory=ImageIOFileRulesModel, title="File Rules" ) diff --git a/server_addon/celaction/server/settings.py b/server_addon/celaction/server/settings.py index 68d1d2dc31..9208948a07 100644 --- a/server_addon/celaction/server/settings.py +++ b/server_addon/celaction/server/settings.py @@ -1,18 +1,17 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField from .imageio import CelActionImageIOModel class CollectRenderPathModel(BaseSettingsModel): - output_extension: str = Field( + output_extension: str = SettingsField( "", title="Output render file extension" ) - anatomy_template_key_render_files: str = Field( + anatomy_template_key_render_files: str = SettingsField( "", title="Anatomy template key: render files" ) - anatomy_template_key_metadata: str = Field( + anatomy_template_key_metadata: str = SettingsField( "", title="Anatomy template key: metadata job file" ) @@ -36,7 +35,7 @@ def _workfile_submit_overrides(): class WorkfileModel(BaseSettingsModel): - submission_overrides: list[str] = Field( + submission_overrides: list[str] = SettingsField( default_factory=list, title="Submission workfile overrides", enum_resolver=_workfile_submit_overrides @@ -44,21 +43,21 @@ class WorkfileModel(BaseSettingsModel): class PublishPuginsModel(BaseSettingsModel): - CollectRenderPath: CollectRenderPathModel = Field( + CollectRenderPath: CollectRenderPathModel = SettingsField( default_factory=CollectRenderPathModel, title="Collect Render Path" ) class CelActionSettings(BaseSettingsModel): - imageio: CelActionImageIOModel = Field( + imageio: CelActionImageIOModel = SettingsField( default_factory=CelActionImageIOModel, title="Color Management (ImageIO)" ) - workfile: WorkfileModel = Field( + workfile: WorkfileModel = SettingsField( title="Workfile" ) - publish: PublishPuginsModel = Field( + publish: PublishPuginsModel = SettingsField( default_factory=PublishPuginsModel, title="Publish plugins", ) diff --git a/server_addon/clockify/server/settings.py b/server_addon/clockify/server/settings.py index 9067cd4243..c01d4c1545 100644 --- a/server_addon/clockify/server/settings.py +++ b/server_addon/clockify/server/settings.py @@ -1,9 +1,8 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class ClockifySettings(BaseSettingsModel): - workspace_name: str = Field( + workspace_name: str = SettingsField( "", title="Workspace name", scope=["studio"] diff --git a/server_addon/core/server/settings/main.py b/server_addon/core/server/settings/main.py index f9e572cbf9..1bdfcefe19 100644 --- a/server_addon/core/server/settings/main.py +++ b/server_addon/core/server/settings/main.py @@ -1,7 +1,8 @@ import json -from pydantic import Field, validator +from pydantic import validator from ayon_server.settings import ( BaseSettingsModel, + SettingsField, MultiplatformPathListModel, ensure_unique_names, task_types_enum, @@ -14,35 +15,35 @@ from .tools import GlobalToolsModel, DEFAULT_TOOLS_VALUES class DiskMappingItemModel(BaseSettingsModel): _layout = "expanded" - source: str = Field("", title="Source") - destination: str = Field("", title="Destination") + source: str = SettingsField("", title="Source") + destination: str = SettingsField("", title="Destination") class DiskMappingModel(BaseSettingsModel): - windows: list[DiskMappingItemModel] = Field( + windows: list[DiskMappingItemModel] = SettingsField( title="Windows", default_factory=list, ) - linux: list[DiskMappingItemModel] = Field( + linux: list[DiskMappingItemModel] = SettingsField( title="Linux", default_factory=list, ) - darwin: list[DiskMappingItemModel] = Field( + darwin: list[DiskMappingItemModel] = SettingsField( title="MacOS", default_factory=list, ) class ImageIOFileRuleModel(BaseSettingsModel): - name: str = Field("", title="Rule name") - pattern: str = Field("", title="Regex pattern") - colorspace: str = Field("", title="Colorspace name") - ext: str = Field("", title="File extension") + name: str = SettingsField("", title="Rule name") + pattern: str = SettingsField("", title="Regex pattern") + colorspace: str = SettingsField("", title="Colorspace name") + ext: str = SettingsField("", title="File extension") class CoreImageIOFileRulesModel(BaseSettingsModel): - activate_global_file_rules: bool = Field(False) - rules: list[ImageIOFileRuleModel] = Field( + activate_global_file_rules: bool = SettingsField(False) + rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, title="Rules" ) @@ -54,19 +55,21 @@ class CoreImageIOFileRulesModel(BaseSettingsModel): class CoreImageIOConfigModel(BaseSettingsModel): - filepath: list[str] = Field(default_factory=list, title="Config path") + filepath: list[str] = SettingsField( + default_factory=list, title="Config path" + ) class CoreImageIOBaseModel(BaseSettingsModel): - activate_global_color_management: bool = Field( + activate_global_color_management: bool = SettingsField( False, title="Enable Color Management" ) - ocio_config: CoreImageIOConfigModel = Field( + ocio_config: CoreImageIOConfigModel = SettingsField( default_factory=CoreImageIOConfigModel, title="OCIO config" ) - file_rules: CoreImageIOFileRulesModel = Field( + file_rules: CoreImageIOFileRulesModel = SettingsField( default_factory=CoreImageIOFileRulesModel, title="File Rules" ) @@ -74,28 +77,28 @@ class CoreImageIOBaseModel(BaseSettingsModel): class VersionStartCategoryProfileModel(BaseSettingsModel): _layout = "expanded" - host_names: list[str] = Field( + host_names: list[str] = SettingsField( default_factory=list, title="Host names" ) - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - task_names: list[str] = Field( + task_names: list[str] = SettingsField( default_factory=list, title="Task names" ) - product_types: list[str] = Field( + product_types: list[str] = SettingsField( default_factory=list, title="Product types" ) - product_names: list[str] = Field( + product_names: list[str] = SettingsField( default_factory=list, title="Product names" ) - version_start: int = Field( + version_start: int = SettingsField( 1, title="Version Start", ge=0 @@ -103,52 +106,52 @@ class VersionStartCategoryProfileModel(BaseSettingsModel): class VersionStartCategoryModel(BaseSettingsModel): - profiles: list[VersionStartCategoryProfileModel] = Field( + profiles: list[VersionStartCategoryProfileModel] = SettingsField( default_factory=list, title="Profiles" ) class CoreSettings(BaseSettingsModel): - studio_name: str = Field("", title="Studio name", scope=["studio"]) - studio_code: str = Field("", title="Studio code", scope=["studio"]) - environments: str = Field( + studio_name: str = SettingsField("", title="Studio name", scope=["studio"]) + studio_code: str = SettingsField("", title="Studio code", scope=["studio"]) + environments: str = SettingsField( "{}", title="Global environment variables", widget="textarea", scope=["studio"], ) - disk_mapping: DiskMappingModel = Field( + disk_mapping: DiskMappingModel = SettingsField( default_factory=DiskMappingModel, title="Disk mapping", ) - tools: GlobalToolsModel = Field( + tools: GlobalToolsModel = SettingsField( default_factory=GlobalToolsModel, title="Tools" ) - version_start_category: VersionStartCategoryModel = Field( + version_start_category: VersionStartCategoryModel = SettingsField( default_factory=VersionStartCategoryModel, title="Version start" ) - imageio: CoreImageIOBaseModel = Field( + imageio: CoreImageIOBaseModel = SettingsField( default_factory=CoreImageIOBaseModel, title="Color Management (ImageIO)" ) - publish: PublishPuginsModel = Field( + publish: PublishPuginsModel = SettingsField( default_factory=PublishPuginsModel, title="Publish plugins" ) - project_plugins: MultiplatformPathListModel = Field( + project_plugins: MultiplatformPathListModel = SettingsField( default_factory=MultiplatformPathListModel, title="Additional Project Plugin Paths", ) - project_folder_structure: str = Field( + project_folder_structure: str = SettingsField( "{}", widget="textarea", title="Project folder structure", section="---" ) - project_environments: str = Field( + project_environments: str = SettingsField( "{}", widget="textarea", title="Project environments", diff --git a/server_addon/core/server/settings/publish_plugins.py b/server_addon/core/server/settings/publish_plugins.py index 0c9b9c96ef..7aa86aafa6 100644 --- a/server_addon/core/server/settings/publish_plugins.py +++ b/server_addon/core/server/settings/publish_plugins.py @@ -1,7 +1,8 @@ -from pydantic import Field, validator +from pydantic import validator from ayon_server.settings import ( BaseSettingsModel, + SettingsField, MultiplatformPathModel, normalize_name, ensure_unique_names, @@ -13,46 +14,46 @@ from ayon_server.types import ColorRGBA_uint8 class ValidateBaseModel(BaseSettingsModel): _isGroup = True - enabled: bool = Field(True) - optional: bool = Field(True, title="Optional") - active: bool = Field(True, title="Active") + enabled: bool = SettingsField(True) + optional: bool = SettingsField(True, title="Optional") + active: bool = SettingsField(True, title="Active") class CollectAnatomyInstanceDataModel(BaseSettingsModel): _isGroup = True - follow_workfile_version: bool = Field( + follow_workfile_version: bool = SettingsField( True, title="Follow workfile version" ) class CollectAudioModel(BaseSettingsModel): _isGroup = True - enabled: bool = Field(True) - audio_product_name: str = Field( + enabled: bool = SettingsField(True) + audio_product_name: str = SettingsField( "", title="Name of audio variant" ) class CollectSceneVersionModel(BaseSettingsModel): _isGroup = True - hosts: list[str] = Field( + hosts: list[str] = SettingsField( default_factory=list, title="Host names" ) - skip_hosts_headless_publish: list[str] = Field( + skip_hosts_headless_publish: list[str] = SettingsField( default_factory=list, title="Skip for host if headless publish" ) class CollectCommentPIModel(BaseSettingsModel): - enabled: bool = Field(True) - families: list[str] = Field(default_factory=list, title="Families") + enabled: bool = SettingsField(True) + families: list[str] = SettingsField(default_factory=list, title="Families") class CollectFramesFixDefModel(BaseSettingsModel): - enabled: bool = Field(True) - rewrite_version_enable: bool = Field( + enabled: bool = SettingsField(True) + rewrite_version_enable: bool = SettingsField( True, title="Show 'Rewrite latest version' toggle" ) @@ -60,15 +61,15 @@ class CollectFramesFixDefModel(BaseSettingsModel): class ValidateIntentProfile(BaseSettingsModel): _layout = "expanded" - hosts: list[str] = Field(default_factory=list, title="Host names") - task_types: list[str] = Field( + hosts: list[str] = SettingsField(default_factory=list, title="Host names") + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - tasks: list[str] = Field(default_factory=list, title="Task names") + tasks: list[str] = SettingsField(default_factory=list, title="Task names") # TODO This was 'validate' in v3 - validate_intent: bool = Field(True, title="Validate") + validate_intent: bool = SettingsField(True, title="Validate") class ValidateIntentModel(BaseSettingsModel): @@ -79,16 +80,16 @@ class ValidateIntentModel(BaseSettingsModel): """ _isGroup = True - enabled: bool = Field(False) - profiles: list[ValidateIntentProfile] = Field(default_factory=list) + enabled: bool = SettingsField(False) + profiles: list[ValidateIntentProfile] = SettingsField(default_factory=list) class ExtractThumbnailFFmpegModel(BaseSettingsModel): - input: list[str] = Field( + input: list[str] = SettingsField( default_factory=list, title="FFmpeg input arguments" ) - output: list[str] = Field( + output: list[str] = SettingsField( default_factory=list, title="FFmpeg input arguments" ) @@ -96,7 +97,7 @@ class ExtractThumbnailFFmpegModel(BaseSettingsModel): class ResizeItemModel(BaseSettingsModel): _layout = "expanded" - width: int = Field( + width: int = SettingsField( 1920, ge=0, le=100000, @@ -104,7 +105,7 @@ class ResizeItemModel(BaseSettingsModel): description="Width and Height must be both set to higher value than 0" " else source resolution is used." ) - height: int = Field( + height: int = SettingsField( 1080, title="Height", ge=0, @@ -121,7 +122,7 @@ _resize_types_enum = [ class ResizeModel(BaseSettingsModel): _layout = "expanded" - type: str = Field( + type: str = SettingsField( title="Type", description="Type of resizing", enum_resolver=lambda: _resize_types_enum, @@ -129,7 +130,7 @@ class ResizeModel(BaseSettingsModel): default="source" ) - resize: ResizeItemModel = Field( + resize: ResizeItemModel = SettingsField( default_factory=ResizeItemModel, title="Resize" ) @@ -143,18 +144,18 @@ _thumbnail_oiio_transcoding_type = [ class DisplayAndViewModel(BaseSettingsModel): _layout = "expanded" - display: str = Field( + display: str = SettingsField( "default", title="Display" ) - view: str = Field( + view: str = SettingsField( "sRGB", title="View" ) class ExtractThumbnailOIIODefaultsModel(BaseSettingsModel): - type: str = Field( + type: str = SettingsField( title="Type", description="Transcoding type", enum_resolver=lambda: _thumbnail_oiio_transcoding_type, @@ -162,11 +163,11 @@ class ExtractThumbnailOIIODefaultsModel(BaseSettingsModel): default="colorspace" ) - colorspace: str = Field( + colorspace: str = SettingsField( "", title="Colorspace" ) - display_and_view: DisplayAndViewModel = Field( + display_and_view: DisplayAndViewModel = SettingsField( default_factory=DisplayAndViewModel, title="Display&View" ) @@ -174,30 +175,30 @@ class ExtractThumbnailOIIODefaultsModel(BaseSettingsModel): class ExtractThumbnailModel(BaseSettingsModel): _isGroup = True - enabled: bool = Field(True) - integrate_thumbnail: bool = Field( + enabled: bool = SettingsField(True) + integrate_thumbnail: bool = SettingsField( True, title="Integrate Thumbnail Representation" ) - target_size: ResizeModel = Field( + target_size: ResizeModel = SettingsField( default_factory=ResizeModel, title="Target size" ) - background_color: ColorRGBA_uint8 = Field( + background_color: ColorRGBA_uint8 = SettingsField( (0, 0, 0, 0.0), title="Background color" ) - duration_split: float = Field( + duration_split: float = SettingsField( 0.5, title="Duration split", ge=0.0, le=1.0 ) - oiiotool_defaults: ExtractThumbnailOIIODefaultsModel = Field( + oiiotool_defaults: ExtractThumbnailOIIODefaultsModel = SettingsField( default_factory=ExtractThumbnailOIIODefaultsModel, title="OIIOtool defaults" ) - ffmpeg_args: ExtractThumbnailFFmpegModel = Field( + ffmpeg_args: ExtractThumbnailFFmpegModel = SettingsField( default_factory=ExtractThumbnailFFmpegModel ) @@ -210,57 +211,59 @@ def _extract_oiio_transcoding_type(): class OIIOToolArgumentsModel(BaseSettingsModel): - additional_command_args: list[str] = Field( + additional_command_args: list[str] = SettingsField( default_factory=list, title="Arguments") class ExtractOIIOTranscodeOutputModel(BaseSettingsModel): _layout = "expanded" - name: str = Field("", title="Name") - extension: str = Field("", title="Extension") - transcoding_type: str = Field( + name: str = SettingsField("", title="Name") + extension: str = SettingsField("", title="Extension") + transcoding_type: str = SettingsField( "colorspace", title="Transcoding type", enum_resolver=_extract_oiio_transcoding_type ) - colorspace: str = Field("", title="Colorspace") - display: str = Field("", title="Display") - view: str = Field("", title="View") - oiiotool_args: OIIOToolArgumentsModel = Field( + colorspace: str = SettingsField("", title="Colorspace") + display: str = SettingsField("", title="Display") + view: str = SettingsField("", title="View") + oiiotool_args: OIIOToolArgumentsModel = SettingsField( default_factory=OIIOToolArgumentsModel, title="OIIOtool arguments") - tags: list[str] = Field(default_factory=list, title="Tags") - custom_tags: list[str] = Field(default_factory=list, title="Custom Tags") + tags: list[str] = SettingsField(default_factory=list, title="Tags") + custom_tags: list[str] = SettingsField( + default_factory=list, title="Custom Tags" + ) class ExtractOIIOTranscodeProfileModel(BaseSettingsModel): - product_types: list[str] = Field( + product_types: list[str] = SettingsField( default_factory=list, title="Product types" ) - hosts: list[str] = Field( + hosts: list[str] = SettingsField( default_factory=list, title="Host names" ) - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - task_names: list[str] = Field( + task_names: list[str] = SettingsField( default_factory=list, title="Task names" ) - product_names: list[str] = Field( + product_names: list[str] = SettingsField( default_factory=list, title="Product names" ) - delete_original: bool = Field( + delete_original: bool = SettingsField( True, title="Delete Original Representation" ) - outputs: list[ExtractOIIOTranscodeOutputModel] = Field( + outputs: list[ExtractOIIOTranscodeOutputModel] = SettingsField( default_factory=list, title="Output Definitions", ) @@ -272,27 +275,27 @@ class ExtractOIIOTranscodeProfileModel(BaseSettingsModel): class ExtractOIIOTranscodeModel(BaseSettingsModel): - enabled: bool = Field(True) - profiles: list[ExtractOIIOTranscodeProfileModel] = Field( + enabled: bool = SettingsField(True) + profiles: list[ExtractOIIOTranscodeProfileModel] = SettingsField( default_factory=list, title="Profiles" ) # --- [START] Extract Review --- class ExtractReviewFFmpegModel(BaseSettingsModel): - video_filters: list[str] = Field( + video_filters: list[str] = SettingsField( default_factory=list, title="Video filters" ) - audio_filters: list[str] = Field( + audio_filters: list[str] = SettingsField( default_factory=list, title="Audio filters" ) - input: list[str] = Field( + input: list[str] = SettingsField( default_factory=list, title="Input arguments" ) - output: list[str] = Field( + output: list[str] = SettingsField( default_factory=list, title="Output arguments" ) @@ -316,11 +319,13 @@ def extract_review_filter_enum(): class ExtractReviewFilterModel(BaseSettingsModel): - families: list[str] = Field(default_factory=list, title="Families") - product_names: list[str] = Field( + families: list[str] = SettingsField(default_factory=list, title="Families") + product_names: list[str] = SettingsField( default_factory=list, title="Product names") - custom_tags: list[str] = Field(default_factory=list, title="Custom Tags") - single_frame_filter: str = Field( + custom_tags: list[str] = SettingsField( + default_factory=list, title="Custom Tags" + ) + single_frame_filter: str = SettingsField( "everytime", description=( "Use output always / only if input is 1 frame" @@ -331,24 +336,24 @@ class ExtractReviewFilterModel(BaseSettingsModel): class ExtractReviewLetterBox(BaseSettingsModel): - enabled: bool = Field(True) - ratio: float = Field( + enabled: bool = SettingsField(True) + ratio: float = SettingsField( 0.0, title="Ratio", ge=0.0, le=10000.0 ) - fill_color: ColorRGBA_uint8 = Field( + fill_color: ColorRGBA_uint8 = SettingsField( (0, 0, 0, 0.0), title="Fill Color" ) - line_thickness: int = Field( + line_thickness: int = SettingsField( 0, title="Line Thickness", ge=0, le=1000 ) - line_color: ColorRGBA_uint8 = Field( + line_color: ColorRGBA_uint8 = SettingsField( (0, 0, 0, 0.0), title="Line Color" ) @@ -356,29 +361,29 @@ class ExtractReviewLetterBox(BaseSettingsModel): class ExtractReviewOutputDefModel(BaseSettingsModel): _layout = "expanded" - name: str = Field("", title="Name") - ext: str = Field("", title="Output extension") + name: str = SettingsField("", title="Name") + ext: str = SettingsField("", title="Output extension") # TODO use some different source of tags - tags: list[str] = Field(default_factory=list, title="Tags") - burnins: list[str] = Field( + tags: list[str] = SettingsField(default_factory=list, title="Tags") + burnins: list[str] = SettingsField( default_factory=list, title="Link to a burnin by name" ) - ffmpeg_args: ExtractReviewFFmpegModel = Field( + ffmpeg_args: ExtractReviewFFmpegModel = SettingsField( default_factory=ExtractReviewFFmpegModel, title="FFmpeg arguments" ) - filter: ExtractReviewFilterModel = Field( + filter: ExtractReviewFilterModel = SettingsField( default_factory=ExtractReviewFilterModel, title="Additional output filtering" ) - overscan_crop: str = Field( + overscan_crop: str = SettingsField( "", title="Overscan crop", description=( "Crop input overscan. See the documentation for more information." ) ) - overscan_color: ColorRGBA_uint8 = Field( + overscan_color: ColorRGBA_uint8 = SettingsField( (0, 0, 0, 0.0), title="Overscan color", description=( @@ -386,7 +391,7 @@ class ExtractReviewOutputDefModel(BaseSettingsModel): " same as output aspect ratio." ) ) - width: int = Field( + width: int = SettingsField( 0, ge=0, le=100000, @@ -396,13 +401,13 @@ class ExtractReviewOutputDefModel(BaseSettingsModel): " value than 0 else source resolution is used." ) ) - height: int = Field( + height: int = SettingsField( 0, title="Output height", ge=0, le=100000, ) - scale_pixel_aspect: bool = Field( + scale_pixel_aspect: bool = SettingsField( True, title="Scale pixel aspect", description=( @@ -410,7 +415,7 @@ class ExtractReviewOutputDefModel(BaseSettingsModel): " Usefull for anamorph reviews." ) ) - bg_color: ColorRGBA_uint8 = Field( + bg_color: ColorRGBA_uint8 = SettingsField( (0, 0, 0, 0.0), description=( "Background color is used only when input have transparency" @@ -418,7 +423,7 @@ class ExtractReviewOutputDefModel(BaseSettingsModel): ), title="Background color", ) - letter_box: ExtractReviewLetterBox = Field( + letter_box: ExtractReviewLetterBox = SettingsField( default_factory=ExtractReviewLetterBox, title="Letter Box" ) @@ -431,14 +436,14 @@ class ExtractReviewOutputDefModel(BaseSettingsModel): class ExtractReviewProfileModel(BaseSettingsModel): _layout = "expanded" - product_types: list[str] = Field( + product_types: list[str] = SettingsField( default_factory=list, title="Product types" ) # TODO use hosts enum - hosts: list[str] = Field( + hosts: list[str] = SettingsField( default_factory=list, title="Host names" ) - outputs: list[ExtractReviewOutputDefModel] = Field( + outputs: list[ExtractReviewOutputDefModel] = SettingsField( default_factory=list, title="Output Definitions" ) @@ -450,8 +455,8 @@ class ExtractReviewProfileModel(BaseSettingsModel): class ExtractReviewModel(BaseSettingsModel): _isGroup = True - enabled: bool = Field(True) - profiles: list[ExtractReviewProfileModel] = Field( + enabled: bool = SettingsField(True) + profiles: list[ExtractReviewProfileModel] = SettingsField( default_factory=list, title="Profiles" ) @@ -460,30 +465,30 @@ class ExtractReviewModel(BaseSettingsModel): # --- [Start] Extract Burnin --- class ExtractBurninOptionsModel(BaseSettingsModel): - font_size: int = Field(0, ge=0, title="Font size") - font_color: ColorRGBA_uint8 = Field( + font_size: int = SettingsField(0, ge=0, title="Font size") + font_color: ColorRGBA_uint8 = SettingsField( (255, 255, 255, 1.0), title="Font color" ) - bg_color: ColorRGBA_uint8 = Field( + bg_color: ColorRGBA_uint8 = SettingsField( (0, 0, 0, 1.0), title="Background color" ) - x_offset: int = Field(0, title="X Offset") - y_offset: int = Field(0, title="Y Offset") - bg_padding: int = Field(0, title="Padding around text") - font_filepath: MultiplatformPathModel = Field( + x_offset: int = SettingsField(0, title="X Offset") + y_offset: int = SettingsField(0, title="Y Offset") + bg_padding: int = SettingsField(0, title="Padding around text") + font_filepath: MultiplatformPathModel = SettingsField( default_factory=MultiplatformPathModel, title="Font file path" ) class ExtractBurninDefFilter(BaseSettingsModel): - families: list[str] = Field( + families: list[str] = SettingsField( default_factory=list, title="Families" ) - tags: list[str] = Field( + tags: list[str] = SettingsField( default_factory=list, title="Tags" ) @@ -492,14 +497,14 @@ class ExtractBurninDefFilter(BaseSettingsModel): class ExtractBurninDef(BaseSettingsModel): _isGroup = True _layout = "expanded" - name: str = Field("") - TOP_LEFT: str = Field("", topic="Top Left") - TOP_CENTERED: str = Field("", topic="Top Centered") - TOP_RIGHT: str = Field("", topic="Top Right") - BOTTOM_LEFT: str = Field("", topic="Bottom Left") - BOTTOM_CENTERED: str = Field("", topic="Bottom Centered") - BOTTOM_RIGHT: str = Field("", topic="Bottom Right") - filter: ExtractBurninDefFilter = Field( + name: str = SettingsField("") + TOP_LEFT: str = SettingsField("", topic="Top Left") + TOP_CENTERED: str = SettingsField("", topic="Top Centered") + TOP_RIGHT: str = SettingsField("", topic="Top Right") + BOTTOM_LEFT: str = SettingsField("", topic="Bottom Left") + BOTTOM_CENTERED: str = SettingsField("", topic="Bottom Centered") + BOTTOM_RIGHT: str = SettingsField("", topic="Bottom Right") + filter: ExtractBurninDefFilter = SettingsField( default_factory=ExtractBurninDefFilter, title="Additional filtering" ) @@ -512,28 +517,28 @@ class ExtractBurninDef(BaseSettingsModel): class ExtractBurninProfile(BaseSettingsModel): _layout = "expanded" - product_types: list[str] = Field( + product_types: list[str] = SettingsField( default_factory=list, title="Produt types" ) - hosts: list[str] = Field( + hosts: list[str] = SettingsField( default_factory=list, title="Host names" ) - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - task_names: list[str] = Field( + task_names: list[str] = SettingsField( default_factory=list, title="Task names" ) - product_names: list[str] = Field( + product_names: list[str] = SettingsField( default_factory=list, title="Product names" ) - burnins: list[ExtractBurninDef] = Field( + burnins: list[ExtractBurninDef] = SettingsField( default_factory=list, title="Burnins" ) @@ -547,12 +552,12 @@ class ExtractBurninProfile(BaseSettingsModel): class ExtractBurninModel(BaseSettingsModel): _isGroup = True - enabled: bool = Field(True) - options: ExtractBurninOptionsModel = Field( + enabled: bool = SettingsField(True) + options: ExtractBurninOptionsModel = SettingsField( default_factory=ExtractBurninOptionsModel, title="Burnin formatting options" ) - profiles: list[ExtractBurninProfile] = Field( + profiles: list[ExtractBurninProfile] = SettingsField( default_factory=list, title="Profiles" ) @@ -561,24 +566,24 @@ class ExtractBurninModel(BaseSettingsModel): class PreIntegrateThumbnailsProfile(BaseSettingsModel): _isGroup = True - product_types: list[str] = Field( + product_types: list[str] = SettingsField( default_factory=list, title="Product types", ) - hosts: list[str] = Field( + hosts: list[str] = SettingsField( default_factory=list, title="Hosts", ) - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - product_names: list[str] = Field( + product_names: list[str] = SettingsField( default_factory=list, title="Product names", ) - integrate_thumbnail: bool = Field(True) + integrate_thumbnail: bool = SettingsField(True) class PreIntegrateThumbnailsModel(BaseSettingsModel): @@ -589,26 +594,26 @@ class PreIntegrateThumbnailsModel(BaseSettingsModel): """ _isGroup = True - enabled: bool = Field(True) - integrate_profiles: list[PreIntegrateThumbnailsProfile] = Field( + enabled: bool = SettingsField(True) + integrate_profiles: list[PreIntegrateThumbnailsProfile] = SettingsField( default_factory=list, title="Integrate profiles" ) class IntegrateProductGroupProfile(BaseSettingsModel): - product_types: list[str] = Field( + product_types: list[str] = SettingsField( default_factory=list, title="Product types" ) - hosts: list[str] = Field(default_factory=list, title="Hosts") - task_types: list[str] = Field( + hosts: list[str] = SettingsField(default_factory=list, title="Hosts") + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - tasks: list[str] = Field(default_factory=list, title="Task names") - template: str = Field("", title="Template") + tasks: list[str] = SettingsField(default_factory=list, title="Task names") + template: str = SettingsField("", title="Template") class IntegrateProductGroupModel(BaseSettingsModel): @@ -622,163 +627,169 @@ class IntegrateProductGroupModel(BaseSettingsModel): """ _isGroup = True - product_grouping_profiles: list[IntegrateProductGroupProfile] = Field( - default_factory=list, - title="Product group profiles" + product_grouping_profiles: list[IntegrateProductGroupProfile] = ( + SettingsField( + default_factory=list, + title="Product group profiles" + ) ) class IntegrateANProductGroupProfileModel(BaseSettingsModel): - product_types: list[str] = Field( + product_types: list[str] = SettingsField( default_factory=list, title="Product types" ) - hosts: list[str] = Field( + hosts: list[str] = SettingsField( default_factory=list, title="Hosts" ) - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - tasks: list[str] = Field( + tasks: list[str] = SettingsField( default_factory=list, title="Task names" ) - template: str = Field("", title="Template") + template: str = SettingsField("", title="Template") class IntegrateANTemplateNameProfileModel(BaseSettingsModel): - product_types: list[str] = Field( + product_types: list[str] = SettingsField( default_factory=list, title="Product types" ) - hosts: list[str] = Field( + hosts: list[str] = SettingsField( default_factory=list, title="Hosts" ) - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - tasks: list[str] = Field( + tasks: list[str] = SettingsField( default_factory=list, title="Task names" ) - template_name: str = Field("", title="Template name") + template_name: str = SettingsField("", title="Template name") class IntegrateHeroTemplateNameProfileModel(BaseSettingsModel): - product_types: list[str] = Field( + product_types: list[str] = SettingsField( default_factory=list, title="Product types" ) - hosts: list[str] = Field( + hosts: list[str] = SettingsField( default_factory=list, title="Hosts" ) - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - task_names: list[str] = Field( + task_names: list[str] = SettingsField( default_factory=list, title="Task names" ) - template_name: str = Field("", title="Template name") + template_name: str = SettingsField("", title="Template name") class IntegrateHeroVersionModel(BaseSettingsModel): _isGroup = True - enabled: bool = Field(True) - optional: bool = Field(False, title="Optional") - active: bool = Field(True, title="Active") - families: list[str] = Field(default_factory=list, title="Families") + enabled: bool = SettingsField(True) + optional: bool = SettingsField(False, title="Optional") + active: bool = SettingsField(True, title="Active") + families: list[str] = SettingsField(default_factory=list, title="Families") class CleanUpModel(BaseSettingsModel): _isGroup = True - paterns: list[str] = Field( + paterns: list[str] = SettingsField( default_factory=list, title="Patterns (regex)" ) - remove_temp_renders: bool = Field(False, title="Remove Temp renders") + remove_temp_renders: bool = SettingsField( + False, title="Remove Temp renders" + ) class CleanUpFarmModel(BaseSettingsModel): _isGroup = True - enabled: bool = Field(True) + enabled: bool = SettingsField(True) class PublishPuginsModel(BaseSettingsModel): - CollectAnatomyInstanceData: CollectAnatomyInstanceDataModel = Field( - default_factory=CollectAnatomyInstanceDataModel, - title="Collect Anatomy Instance Data" + CollectAnatomyInstanceData: CollectAnatomyInstanceDataModel = ( + SettingsField( + default_factory=CollectAnatomyInstanceDataModel, + title="Collect Anatomy Instance Data" + ) ) - CollectAudio: CollectAudioModel = Field( + CollectAudio: CollectAudioModel = SettingsField( default_factory=CollectAudioModel, title="Collect Audio" ) - CollectSceneVersion: CollectSceneVersionModel = Field( + CollectSceneVersion: CollectSceneVersionModel = SettingsField( default_factory=CollectSceneVersionModel, title="Collect Version from Workfile" ) - collect_comment_per_instance: CollectCommentPIModel = Field( + collect_comment_per_instance: CollectCommentPIModel = SettingsField( default_factory=CollectCommentPIModel, title="Collect comment per instance", ) - CollectFramesFixDef: CollectFramesFixDefModel = Field( + CollectFramesFixDef: CollectFramesFixDefModel = SettingsField( default_factory=CollectFramesFixDefModel, title="Collect Frames to Fix", ) - ValidateEditorialAssetName: ValidateBaseModel = Field( + ValidateEditorialAssetName: ValidateBaseModel = SettingsField( default_factory=ValidateBaseModel, title="Validate Editorial Asset Name" ) - ValidateVersion: ValidateBaseModel = Field( + ValidateVersion: ValidateBaseModel = SettingsField( default_factory=ValidateBaseModel, title="Validate Version" ) - ValidateIntent: ValidateIntentModel = Field( + ValidateIntent: ValidateIntentModel = SettingsField( default_factory=ValidateIntentModel, title="Validate Intent" ) - ExtractThumbnail: ExtractThumbnailModel = Field( + ExtractThumbnail: ExtractThumbnailModel = SettingsField( default_factory=ExtractThumbnailModel, title="Extract Thumbnail" ) - ExtractOIIOTranscode: ExtractOIIOTranscodeModel = Field( + ExtractOIIOTranscode: ExtractOIIOTranscodeModel = SettingsField( default_factory=ExtractOIIOTranscodeModel, title="Extract OIIO Transcode" ) - ExtractReview: ExtractReviewModel = Field( + ExtractReview: ExtractReviewModel = SettingsField( default_factory=ExtractReviewModel, title="Extract Review" ) - ExtractBurnin: ExtractBurninModel = Field( + ExtractBurnin: ExtractBurninModel = SettingsField( default_factory=ExtractBurninModel, title="Extract Burnin" ) - PreIntegrateThumbnails: PreIntegrateThumbnailsModel = Field( + PreIntegrateThumbnails: PreIntegrateThumbnailsModel = SettingsField( default_factory=PreIntegrateThumbnailsModel, title="Override Integrate Thumbnail Representations" ) - IntegrateProductGroup: IntegrateProductGroupModel = Field( + IntegrateProductGroup: IntegrateProductGroupModel = SettingsField( default_factory=IntegrateProductGroupModel, title="Integrate Product Group" ) - IntegrateHeroVersion: IntegrateHeroVersionModel = Field( + IntegrateHeroVersion: IntegrateHeroVersionModel = SettingsField( default_factory=IntegrateHeroVersionModel, title="Integrate Hero Version" ) - CleanUp: CleanUpModel = Field( + CleanUp: CleanUpModel = SettingsField( default_factory=CleanUpModel, title="Clean Up" ) - CleanUpFarm: CleanUpFarmModel = Field( + CleanUpFarm: CleanUpFarmModel = SettingsField( default_factory=CleanUpFarmModel, title="Clean Up Farm" ) diff --git a/server_addon/core/server/settings/tools.py b/server_addon/core/server/settings/tools.py index 0dd9d396ae..b45f9b49d4 100644 --- a/server_addon/core/server/settings/tools.py +++ b/server_addon/core/server/settings/tools.py @@ -1,6 +1,7 @@ -from pydantic import Field, validator +from pydantic import validator from ayon_server.settings import ( BaseSettingsModel, + SettingsField, normalize_name, ensure_unique_names, task_types_enum, @@ -9,8 +10,10 @@ from ayon_server.settings import ( class ProductTypeSmartSelectModel(BaseSettingsModel): _layout = "expanded" - name: str = Field("", title="Product type") - task_names: list[str] = Field(default_factory=list, title="Task names") + name: str = SettingsField("", title="Product type") + task_names: list[str] = SettingsField( + default_factory=list, title="Task names" + ) @validator("name") def normalize_value(cls, value): @@ -19,26 +22,28 @@ class ProductTypeSmartSelectModel(BaseSettingsModel): class ProductNameProfile(BaseSettingsModel): _layout = "expanded" - product_types: list[str] = Field( + product_types: list[str] = SettingsField( default_factory=list, title="Product types" ) - hosts: list[str] = Field(default_factory=list, title="Hosts") - task_types: list[str] = Field( + hosts: list[str] = SettingsField(default_factory=list, title="Hosts") + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - tasks: list[str] = Field(default_factory=list, title="Task names") - template: str = Field("", title="Template") + tasks: list[str] = SettingsField(default_factory=list, title="Task names") + template: str = SettingsField("", title="Template") class CreatorToolModel(BaseSettingsModel): # TODO this was dynamic dictionary '{name: task_names}' - product_types_smart_select: list[ProductTypeSmartSelectModel] = Field( - default_factory=list, - title="Create Smart Select" + product_types_smart_select: list[ProductTypeSmartSelectModel] = ( + SettingsField( + default_factory=list, + title="Create Smart Select" + ) ) - product_name_profiles: list[ProductNameProfile] = Field( + product_name_profiles: list[ProductNameProfile] = SettingsField( default_factory=list, title="Product name profiles" ) @@ -51,29 +56,29 @@ class CreatorToolModel(BaseSettingsModel): class WorkfileTemplateProfile(BaseSettingsModel): _layout = "expanded" - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) # TODO this should use hosts enum - hosts: list[str] = Field(default_factory=list, title="Hosts") + hosts: list[str] = SettingsField(default_factory=list, title="Hosts") # TODO this was using project anatomy template name - workfile_template: str = Field("", title="Workfile template") + workfile_template: str = SettingsField("", title="Workfile template") class LastWorkfileOnStartupProfile(BaseSettingsModel): _layout = "expanded" # TODO this should use hosts enum - hosts: list[str] = Field(default_factory=list, title="Hosts") - task_types: list[str] = Field( + hosts: list[str] = SettingsField(default_factory=list, title="Hosts") + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - tasks: list[str] = Field(default_factory=list, title="Task names") - enabled: bool = Field(True, title="Enabled") - use_last_published_workfile: bool = Field( + tasks: list[str] = SettingsField(default_factory=list, title="Task names") + enabled: bool = SettingsField(True, title="Enabled") + use_last_published_workfile: bool = SettingsField( True, title="Use last published workfile" ) @@ -81,54 +86,60 @@ class LastWorkfileOnStartupProfile(BaseSettingsModel): class WorkfilesToolOnStartupProfile(BaseSettingsModel): _layout = "expanded" # TODO this should use hosts enum - hosts: list[str] = Field(default_factory=list, title="Hosts") - task_types: list[str] = Field( + hosts: list[str] = SettingsField(default_factory=list, title="Hosts") + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - tasks: list[str] = Field(default_factory=list, title="Task names") - enabled: bool = Field(True, title="Enabled") + tasks: list[str] = SettingsField(default_factory=list, title="Task names") + enabled: bool = SettingsField(True, title="Enabled") class ExtraWorkFoldersProfile(BaseSettingsModel): _layout = "expanded" # TODO this should use hosts enum - hosts: list[str] = Field(default_factory=list, title="Hosts") - task_types: list[str] = Field( + hosts: list[str] = SettingsField(default_factory=list, title="Hosts") + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - task_names: list[str] = Field(default_factory=list, title="Task names") - folders: list[str] = Field(default_factory=list, title="Folders") + task_names: list[str] = SettingsField( + default_factory=list, title="Task names" + ) + folders: list[str] = SettingsField(default_factory=list, title="Folders") class WorkfilesLockProfile(BaseSettingsModel): _layout = "expanded" # TODO this should use hosts enum - host_names: list[str] = Field(default_factory=list, title="Hosts") - enabled: bool = Field(True, title="Enabled") + host_names: list[str] = SettingsField(default_factory=list, title="Hosts") + enabled: bool = SettingsField(True, title="Enabled") class WorkfilesToolModel(BaseSettingsModel): - workfile_template_profiles: list[WorkfileTemplateProfile] = Field( + workfile_template_profiles: list[WorkfileTemplateProfile] = SettingsField( default_factory=list, title="Workfile template profiles" ) - last_workfile_on_startup: list[LastWorkfileOnStartupProfile] = Field( - default_factory=list, - title="Open last workfile on launch" + last_workfile_on_startup: list[LastWorkfileOnStartupProfile] = ( + SettingsField( + default_factory=list, + title="Open last workfile on launch" + ) ) - open_workfile_tool_on_startup: list[WorkfilesToolOnStartupProfile] = Field( - default_factory=list, - title="Open workfile tool on launch" + open_workfile_tool_on_startup: list[WorkfilesToolOnStartupProfile] = ( + SettingsField( + default_factory=list, + title="Open workfile tool on launch" + ) ) - extra_folders: list[ExtraWorkFoldersProfile] = Field( + extra_folders: list[ExtraWorkFoldersProfile] = SettingsField( default_factory=list, title="Extra work folders" ) - workfile_lock_profiles: list[WorkfilesLockProfile] = Field( + workfile_lock_profiles: list[WorkfilesLockProfile] = SettingsField( default_factory=list, title="Workfile lock profiles" ) @@ -175,95 +186,100 @@ def _product_types_enum(): class LoaderProductTypeFilterProfile(BaseSettingsModel): _layout = "expanded" # TODO this should use hosts enum - hosts: list[str] = Field(default_factory=list, title="Hosts") - task_types: list[str] = Field( + hosts: list[str] = SettingsField(default_factory=list, title="Hosts") + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - is_include: bool = Field(True, title="Exclude / Include") - filter_product_types: list[str] = Field( + is_include: bool = SettingsField(True, title="Exclude / Include") + filter_product_types: list[str] = SettingsField( default_factory=list, enum_resolver=_product_types_enum ) class LoaderToolModel(BaseSettingsModel): - product_type_filter_profiles: list[LoaderProductTypeFilterProfile] = Field( - default_factory=list, - title="Product type filtering" + product_type_filter_profiles: list[LoaderProductTypeFilterProfile] = ( + SettingsField(default_factory=list, title="Product type filtering") ) class PublishTemplateNameProfile(BaseSettingsModel): _layout = "expanded" - product_types: list[str] = Field( + product_types: list[str] = SettingsField( default_factory=list, title="Product types" ) # TODO this should use hosts enum - hosts: list[str] = Field(default_factory=list, title="Hosts") - task_types: list[str] = Field( + hosts: list[str] = SettingsField(default_factory=list, title="Hosts") + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - task_names: list[str] = Field(default_factory=list, title="Task names") - template_name: str = Field("", title="Template name") + task_names: list[str] = SettingsField( + default_factory=list, title="Task names" + ) + template_name: str = SettingsField("", title="Template name") class CustomStagingDirProfileModel(BaseSettingsModel): - active: bool = Field(True, title="Is active") - hosts: list[str] = Field(default_factory=list, title="Host names") - task_types: list[str] = Field( + active: bool = SettingsField(True, title="Is active") + hosts: list[str] = SettingsField(default_factory=list, title="Host names") + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - task_names: list[str] = Field( + task_names: list[str] = SettingsField( default_factory=list, title="Task names" ) - product_types: list[str] = Field( + product_types: list[str] = SettingsField( default_factory=list, title="Product types" ) - product_names: list[str] = Field( + product_names: list[str] = SettingsField( default_factory=list, title="Product names" ) - custom_staging_dir_persistent: bool = Field( + custom_staging_dir_persistent: bool = SettingsField( False, title="Custom Staging Folder Persistent" ) - template_name: str = Field("", title="Template Name") + template_name: str = SettingsField("", title="Template Name") class PublishToolModel(BaseSettingsModel): - template_name_profiles: list[PublishTemplateNameProfile] = Field( + template_name_profiles: list[PublishTemplateNameProfile] = SettingsField( default_factory=list, title="Template name profiles" ) - hero_template_name_profiles: list[PublishTemplateNameProfile] = Field( - default_factory=list, - title="Hero template name profiles" + hero_template_name_profiles: list[PublishTemplateNameProfile] = ( + SettingsField( + default_factory=list, + title="Hero template name profiles" + ) ) - custom_staging_dir_profiles: list[CustomStagingDirProfileModel] = Field( - default_factory=list, - title="Custom Staging Dir Profiles" + custom_staging_dir_profiles: list[CustomStagingDirProfileModel] = ( + SettingsField( + default_factory=list, + title="Custom Staging Dir Profiles" + ) ) class GlobalToolsModel(BaseSettingsModel): - creator: CreatorToolModel = Field( + creator: CreatorToolModel = SettingsField( default_factory=CreatorToolModel, title="Creator" ) - Workfiles: WorkfilesToolModel = Field( + Workfiles: WorkfilesToolModel = SettingsField( default_factory=WorkfilesToolModel, title="Workfiles" ) - loader: LoaderToolModel = Field( + loader: LoaderToolModel = SettingsField( default_factory=LoaderToolModel, title="Loader" ) - publish: PublishToolModel = Field( + publish: PublishToolModel = SettingsField( default_factory=PublishToolModel, title="Publish" ) diff --git a/server_addon/deadline/server/settings/main.py b/server_addon/deadline/server/settings/main.py index f766ef9db8..9537d6d550 100644 --- a/server_addon/deadline/server/settings/main.py +++ b/server_addon/deadline/server/settings/main.py @@ -1,6 +1,10 @@ -from pydantic import Field, validator +from pydantic import validator -from ayon_server.settings import BaseSettingsModel, ensure_unique_names +from ayon_server.settings import ( + BaseSettingsModel, + SettingsField, + ensure_unique_names, +) from .publish_plugins import ( PublishPluginsModel, @@ -10,8 +14,8 @@ from .publish_plugins import ( class ServerListSubmodel(BaseSettingsModel): _layout = "compact" - name: str = Field(title="Name") - value: str = Field(title="Value") + name: str = SettingsField(title="Name") + value: str = SettingsField(title="Value") async def defined_deadline_ws_name_enum_resolver( @@ -33,18 +37,18 @@ async def defined_deadline_ws_name_enum_resolver( class DeadlineSettings(BaseSettingsModel): - deadline_urls: list[ServerListSubmodel] = Field( + deadline_urls: list[ServerListSubmodel] = SettingsField( default_factory=list, title="System Deadline Webservice URLs", scope=["studio"], ) - deadline_server: str = Field( + deadline_server: str = SettingsField( title="Project deadline server", section="---", scope=["project"], enum_resolver=defined_deadline_ws_name_enum_resolver ) - publish: PublishPluginsModel = Field( + publish: PublishPluginsModel = SettingsField( default_factory=PublishPluginsModel, title="Publish Plugins", ) diff --git a/server_addon/deadline/server/settings/publish_plugins.py b/server_addon/deadline/server/settings/publish_plugins.py index a989f3ad9d..8abe59674b 100644 --- a/server_addon/deadline/server/settings/publish_plugins.py +++ b/server_addon/deadline/server/settings/publish_plugins.py @@ -1,26 +1,30 @@ -from pydantic import Field, validator +from pydantic import validator -from ayon_server.settings import BaseSettingsModel, ensure_unique_names +from ayon_server.settings import ( + BaseSettingsModel, + SettingsField, + ensure_unique_names, +) class CollectDeadlinePoolsModel(BaseSettingsModel): """Settings Deadline default pools.""" - primary_pool: str = Field(title="Primary Pool") + primary_pool: str = SettingsField(title="Primary Pool") - secondary_pool: str = Field(title="Secondary Pool") + secondary_pool: str = SettingsField(title="Secondary Pool") class ValidateExpectedFilesModel(BaseSettingsModel): - enabled: bool = Field(True, title="Enabled") - active: bool = Field(True, title="Active") - allow_user_override: bool = Field( + enabled: bool = SettingsField(True, title="Enabled") + active: bool = SettingsField(True, title="Active") + allow_user_override: bool = SettingsField( True, title="Allow user change frame range" ) - families: list[str] = Field( + families: list[str] = SettingsField( default_factory=list, title="Trigger on families" ) - targets: list[str] = Field( + targets: list[str] = SettingsField( default_factory=list, title="Trigger for plugins" ) @@ -45,74 +49,76 @@ def tile_assembler_enum(): class ScenePatchesSubmodel(BaseSettingsModel): _layout = "expanded" - name: str = Field(title="Patch name") - regex: str = Field(title="Patch regex") - line: str = Field(title="Patch line") + name: str = SettingsField(title="Patch name") + regex: str = SettingsField(title="Patch regex") + line: str = SettingsField(title="Patch line") class MayaSubmitDeadlineModel(BaseSettingsModel): """Maya deadline submitter settings.""" - enabled: bool = Field(title="Enabled") - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") - use_published: bool = Field(title="Use Published scene") - import_reference: bool = Field(title="Use Scene with Imported Reference") - asset_dependencies: bool = Field(title="Use Asset dependencies") - priority: int = Field(title="Priority") - tile_priority: int = Field(title="Tile Priority") - group: str = Field(title="Group") - limit: list[str] = Field( + enabled: bool = SettingsField(title="Enabled") + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") + use_published: bool = SettingsField(title="Use Published scene") + import_reference: bool = SettingsField( + title="Use Scene with Imported Reference" + ) + asset_dependencies: bool = SettingsField(title="Use Asset dependencies") + priority: int = SettingsField(title="Priority") + tile_priority: int = SettingsField(title="Tile Priority") + group: str = SettingsField(title="Group") + limit: list[str] = SettingsField( default_factory=list, title="Limit Groups" ) - tile_assembler_plugin: str = Field( + tile_assembler_plugin: str = SettingsField( title="Tile Assembler Plugin", enum_resolver=tile_assembler_enum, ) - jobInfo: str = Field( + jobInfo: str = SettingsField( title="Additional JobInfo data", widget="textarea", ) - pluginInfo: str = Field( + pluginInfo: str = SettingsField( title="Additional PluginInfo data", widget="textarea", ) - scene_patches: list[ScenePatchesSubmodel] = Field( + scene_patches: list[ScenePatchesSubmodel] = SettingsField( default_factory=list, title="Scene patches", ) - strict_error_checking: bool = Field( + strict_error_checking: bool = SettingsField( title="Disable Strict Error Check profiles" ) - @validator("limit", "scene_patches") + @validator("scene_patches") def validate_unique_names(cls, value): ensure_unique_names(value) return value class MaxSubmitDeadlineModel(BaseSettingsModel): - enabled: bool = Field(True) - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") - use_published: bool = Field(title="Use Published scene") - priority: int = Field(title="Priority") - chunk_size: int = Field(title="Frame per Task") - group: str = Field("", title="Group Name") + enabled: bool = SettingsField(True) + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") + use_published: bool = SettingsField(title="Use Published scene") + priority: int = SettingsField(title="Priority") + chunk_size: int = SettingsField(title="Frame per Task") + group: str = SettingsField("", title="Group Name") class EnvSearchReplaceSubmodel(BaseSettingsModel): _layout = "compact" - name: str = Field(title="Name") - value: str = Field(title="Value") + name: str = SettingsField(title="Name") + value: str = SettingsField(title="Value") class LimitGroupsSubmodel(BaseSettingsModel): _layout = "expanded" - name: str = Field(title="Name") - value: list[str] = Field( + name: str = SettingsField(title="Name") + value: list[str] = SettingsField( default_factory=list, title="Limit Groups" ) @@ -137,14 +143,16 @@ def fusion_deadline_plugin_enum(): class FusionSubmitDeadlineModel(BaseSettingsModel): - enabled: bool = Field(True, title="Enabled") - optional: bool = Field(False, title="Optional") - active: bool = Field(True, title="Active") - priority: int = Field(50, title="Priority") - chunk_size: int = Field(10, title="Frame per Task") - concurrent_tasks: int = Field(1, title="Number of concurrent tasks") - group: str = Field("", title="Group Name") - plugin: str = Field("Fusion", + enabled: bool = SettingsField(True, title="Enabled") + optional: bool = SettingsField(False, title="Optional") + active: bool = SettingsField(True, title="Active") + priority: int = SettingsField(50, title="Priority") + chunk_size: int = SettingsField(10, title="Frame per Task") + concurrent_tasks: int = SettingsField( + 1, title="Number of concurrent tasks" + ) + group: str = SettingsField("", title="Group Name") + plugin: str = SettingsField("Fusion", enum_resolver=fusion_deadline_plugin_enum, title="Deadline Plugin") @@ -152,32 +160,39 @@ class FusionSubmitDeadlineModel(BaseSettingsModel): class NukeSubmitDeadlineModel(BaseSettingsModel): """Nuke deadline submitter settings.""" - enabled: bool = Field(title="Enabled") - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") - priority: int = Field(title="Priority") - chunk_size: int = Field(title="Chunk Size") - concurrent_tasks: int = Field(title="Number of concurrent tasks") - group: str = Field(title="Group") - department: str = Field(title="Department") - use_gpu: bool = Field(title="Use GPU") + enabled: bool = SettingsField(title="Enabled") + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") + priority: int = SettingsField(title="Priority") + chunk_size: int = SettingsField(title="Chunk Size") + concurrent_tasks: int = SettingsField(title="Number of concurrent tasks") + group: str = SettingsField(title="Group") + department: str = SettingsField(title="Department") + use_gpu: bool = SettingsField(title="Use GPU") + workfile_dependency: bool = SettingsField(title="Workfile Dependency") + use_published_workfile: bool = SettingsField( + title="Use Published Workfile" + ) - env_allowed_keys: list[str] = Field( + env_allowed_keys: list[str] = SettingsField( default_factory=list, title="Allowed environment keys" ) - env_search_replace_values: list[EnvSearchReplaceSubmodel] = Field( + env_search_replace_values: list[EnvSearchReplaceSubmodel] = SettingsField( default_factory=list, title="Search & replace in environment values", ) - limit_groups: list[LimitGroupsSubmodel] = Field( + limit_groups: list[LimitGroupsSubmodel] = SettingsField( default_factory=list, title="Limit Groups", ) - @validator("limit_groups", "env_allowed_keys", "env_search_replace_values") + @validator( + "limit_groups", + "env_allowed_keys", + "env_search_replace_values") def validate_unique_names(cls, value): ensure_unique_names(value) return value @@ -186,58 +201,62 @@ class NukeSubmitDeadlineModel(BaseSettingsModel): class HarmonySubmitDeadlineModel(BaseSettingsModel): """Harmony deadline submitter settings.""" - enabled: bool = Field(title="Enabled") - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") - use_published: bool = Field(title="Use Published scene") - priority: int = Field(title="Priority") - chunk_size: int = Field(title="Chunk Size") - group: str = Field(title="Group") - department: str = Field(title="Department") + enabled: bool = SettingsField(title="Enabled") + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") + use_published: bool = SettingsField(title="Use Published scene") + priority: int = SettingsField(title="Priority") + chunk_size: int = SettingsField(title="Chunk Size") + group: str = SettingsField(title="Group") + department: str = SettingsField(title="Department") class AfterEffectsSubmitDeadlineModel(BaseSettingsModel): """After Effects deadline submitter settings.""" - enabled: bool = Field(title="Enabled") - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") - use_published: bool = Field(title="Use Published scene") - priority: int = Field(title="Priority") - chunk_size: int = Field(title="Chunk Size") - group: str = Field(title="Group") - department: str = Field(title="Department") - multiprocess: bool = Field(title="Optional") + enabled: bool = SettingsField(title="Enabled") + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") + use_published: bool = SettingsField(title="Use Published scene") + priority: int = SettingsField(title="Priority") + chunk_size: int = SettingsField(title="Chunk Size") + group: str = SettingsField(title="Group") + department: str = SettingsField(title="Department") + multiprocess: bool = SettingsField(title="Optional") class CelactionSubmitDeadlineModel(BaseSettingsModel): - enabled: bool = Field(True, title="Enabled") - deadline_department: str = Field("", title="Deadline apartment") - deadline_priority: int = Field(50, title="Deadline priority") - deadline_pool: str = Field("", title="Deadline pool") - deadline_pool_secondary: str = Field("", title="Deadline pool (secondary)") - deadline_group: str = Field("", title="Deadline Group") - deadline_chunk_size: int = Field(10, title="Deadline Chunk size") - deadline_job_delay: str = Field( + enabled: bool = SettingsField(True, title="Enabled") + deadline_department: str = SettingsField("", title="Deadline apartment") + deadline_priority: int = SettingsField(50, title="Deadline priority") + deadline_pool: str = SettingsField("", title="Deadline pool") + deadline_pool_secondary: str = SettingsField( + "", title="Deadline pool (secondary)" + ) + deadline_group: str = SettingsField("", title="Deadline Group") + deadline_chunk_size: int = SettingsField(10, title="Deadline Chunk size") + deadline_job_delay: str = SettingsField( "", title="Delay job (timecode dd:hh:mm:ss)" ) class BlenderSubmitDeadlineModel(BaseSettingsModel): - enabled: bool = Field(True) - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") - use_published: bool = Field(title="Use Published scene") - priority: int = Field(title="Priority") - chunk_size: int = Field(title="Frame per Task") - group: str = Field("", title="Group Name") - job_delay: str = Field("", title="Delay job (timecode dd:hh:mm:ss)") + enabled: bool = SettingsField(True) + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") + use_published: bool = SettingsField(title="Use Published scene") + priority: int = SettingsField(title="Priority") + chunk_size: int = SettingsField(title="Frame per Task") + group: str = SettingsField("", title="Group Name") + job_delay: str = SettingsField( + "", title="Delay job (timecode dd:hh:mm:ss)" + ) class AOVFilterSubmodel(BaseSettingsModel): _layout = "expanded" - name: str = Field(title="Host") - value: list[str] = Field( + name: str = SettingsField(title="Host") + value: list[str] = SettingsField( default_factory=list, title="AOV regex" ) @@ -246,29 +265,29 @@ class AOVFilterSubmodel(BaseSettingsModel): class ProcessCacheJobFarmModel(BaseSettingsModel): """Process submitted job on farm.""" - enabled: bool = Field(title="Enabled") - deadline_department: str = Field(title="Department") - deadline_pool: str = Field(title="Pool") - deadline_group: str = Field(title="Group") - deadline_chunk_size: int = Field(title="Chunk Size") - deadline_priority: int = Field(title="Priority") + enabled: bool = SettingsField(title="Enabled") + deadline_department: str = SettingsField(title="Department") + deadline_pool: str = SettingsField(title="Pool") + deadline_group: str = SettingsField(title="Group") + deadline_chunk_size: int = SettingsField(title="Chunk Size") + deadline_priority: int = SettingsField(title="Priority") class ProcessSubmittedJobOnFarmModel(BaseSettingsModel): """Process submitted job on farm.""" - enabled: bool = Field(title="Enabled") - deadline_department: str = Field(title="Department") - deadline_pool: str = Field(title="Pool") - deadline_group: str = Field(title="Group") - deadline_chunk_size: int = Field(title="Chunk Size") - deadline_priority: int = Field(title="Priority") - publishing_script: str = Field(title="Publishing script path") - skip_integration_repre_list: list[str] = Field( + enabled: bool = SettingsField(title="Enabled") + deadline_department: str = SettingsField(title="Department") + deadline_pool: str = SettingsField(title="Pool") + deadline_group: str = SettingsField(title="Group") + deadline_chunk_size: int = SettingsField(title="Chunk Size") + deadline_priority: int = SettingsField(title="Priority") + publishing_script: str = SettingsField(title="Publishing script path") + skip_integration_repre_list: list[str] = SettingsField( default_factory=list, title="Skip integration of representation with ext" ) - aov_filter: list[AOVFilterSubmodel] = Field( + aov_filter: list[AOVFilterSubmodel] = SettingsField( default_factory=list, title="Reviewable products filter", ) @@ -280,41 +299,44 @@ class ProcessSubmittedJobOnFarmModel(BaseSettingsModel): class PublishPluginsModel(BaseSettingsModel): - CollectDeadlinePools: CollectDeadlinePoolsModel = Field( + CollectDeadlinePools: CollectDeadlinePoolsModel = SettingsField( default_factory=CollectDeadlinePoolsModel, title="Default Pools") - ValidateExpectedFiles: ValidateExpectedFilesModel = Field( + ValidateExpectedFiles: ValidateExpectedFilesModel = SettingsField( default_factory=ValidateExpectedFilesModel, title="Validate Expected Files" ) - MayaSubmitDeadline: MayaSubmitDeadlineModel = Field( + MayaSubmitDeadline: MayaSubmitDeadlineModel = SettingsField( default_factory=MayaSubmitDeadlineModel, title="Maya Submit to deadline") - MaxSubmitDeadline: MaxSubmitDeadlineModel = Field( + MaxSubmitDeadline: MaxSubmitDeadlineModel = SettingsField( default_factory=MaxSubmitDeadlineModel, title="Max Submit to deadline") - FusionSubmitDeadline: FusionSubmitDeadlineModel = Field( + FusionSubmitDeadline: FusionSubmitDeadlineModel = SettingsField( default_factory=FusionSubmitDeadlineModel, title="Fusion submit to Deadline") - NukeSubmitDeadline: NukeSubmitDeadlineModel = Field( + NukeSubmitDeadline: NukeSubmitDeadlineModel = SettingsField( default_factory=NukeSubmitDeadlineModel, title="Nuke Submit to deadline") - HarmonySubmitDeadline: HarmonySubmitDeadlineModel = Field( + HarmonySubmitDeadline: HarmonySubmitDeadlineModel = SettingsField( default_factory=HarmonySubmitDeadlineModel, title="Harmony Submit to deadline") - AfterEffectsSubmitDeadline: AfterEffectsSubmitDeadlineModel = Field( - default_factory=AfterEffectsSubmitDeadlineModel, - title="After Effects to deadline") - CelactionSubmitDeadline: CelactionSubmitDeadlineModel = Field( + AfterEffectsSubmitDeadline: AfterEffectsSubmitDeadlineModel = ( + SettingsField( + default_factory=AfterEffectsSubmitDeadlineModel, + title="After Effects to deadline" + ) + ) + CelactionSubmitDeadline: CelactionSubmitDeadlineModel = SettingsField( default_factory=CelactionSubmitDeadlineModel, title="Celaction Submit Deadline") - BlenderSubmitDeadline: BlenderSubmitDeadlineModel = Field( + BlenderSubmitDeadline: BlenderSubmitDeadlineModel = SettingsField( default_factory=BlenderSubmitDeadlineModel, title="Blender Submit Deadline") - ProcessSubmittedCacheJobOnFarm: ProcessCacheJobFarmModel = Field( + ProcessSubmittedCacheJobOnFarm: ProcessCacheJobFarmModel = SettingsField( default_factory=ProcessCacheJobFarmModel, title="Process submitted cache Job on farm.") - ProcessSubmittedJobOnFarm: ProcessSubmittedJobOnFarmModel = Field( + ProcessSubmittedJobOnFarm: ProcessSubmittedJobOnFarmModel = SettingsField( default_factory=ProcessSubmittedJobOnFarmModel, title="Process submitted job on farm.") @@ -382,6 +404,8 @@ DEFAULT_DEADLINE_PLUGINS_SETTINGS = { "group": "", "department": "", "use_gpu": True, + "workfile_dependency": True, + "use_published_workfile": True, "env_allowed_keys": [], "env_search_replace_values": [], "limit_groups": [] diff --git a/server_addon/deadline/server/version.py b/server_addon/deadline/server/version.py index 0a8da88258..9cb17e7976 100644 --- a/server_addon/deadline/server/version.py +++ b/server_addon/deadline/server/version.py @@ -1 +1 @@ -__version__ = "0.1.6" +__version__ = "0.1.8" diff --git a/server_addon/flame/server/settings/create_plugins.py b/server_addon/flame/server/settings/create_plugins.py index 374a7368d2..44fb8a2e91 100644 --- a/server_addon/flame/server/settings/create_plugins.py +++ b/server_addon/flame/server/settings/create_plugins.py @@ -1,95 +1,94 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class CreateShotClipModel(BaseSettingsModel): - hierarchy: str = Field( + hierarchy: str = SettingsField( "shot", title="Shot parent hierarchy", section="Shot Hierarchy And Rename Settings" ) - useShotName: bool = Field( + useShotName: bool = SettingsField( True, title="Use Shot Name", ) - clipRename: bool = Field( + clipRename: bool = SettingsField( False, title="Rename clips", ) - clipName: str = Field( + clipName: str = SettingsField( "{sequence}{shot}", title="Clip name template" ) - segmentIndex: bool = Field( + segmentIndex: bool = SettingsField( True, title="Accept segment order" ) - countFrom: int = Field( + countFrom: int = SettingsField( 10, title="Count sequence from" ) - countSteps: int = Field( + countSteps: int = SettingsField( 10, title="Stepping number" ) - folder: str = Field( + folder: str = SettingsField( "shots", title="{folder}", section="Shot Template Keywords" ) - episode: str = Field( + episode: str = SettingsField( "ep01", title="{episode}" ) - sequence: str = Field( + sequence: str = SettingsField( "a", title="{sequence}" ) - track: str = Field( + track: str = SettingsField( "{_track_}", title="{track}" ) - shot: str = Field( + shot: str = SettingsField( "####", title="{shot}" ) - vSyncOn: bool = Field( + vSyncOn: bool = SettingsField( False, title="Enable Vertical Sync", section="Vertical Synchronization Of Attributes" ) - workfileFrameStart: int = Field( + workfileFrameStart: int = SettingsField( 1001, title="Workfiles Start Frame", section="Shot Attributes" ) - handleStart: int = Field( + handleStart: int = SettingsField( 10, title="Handle start (head)" ) - handleEnd: int = Field( + handleEnd: int = SettingsField( 10, title="Handle end (tail)" ) - includeHandles: bool = Field( + includeHandles: bool = SettingsField( False, title="Enable handles including" ) - retimedHandles: bool = Field( + retimedHandles: bool = SettingsField( True, title="Enable retimed handles" ) - retimedFramerange: bool = Field( + retimedFramerange: bool = SettingsField( True, title="Enable retimed shot frameranges" ) class CreatePuginsModel(BaseSettingsModel): - CreateShotClip: CreateShotClipModel = Field( + CreateShotClip: CreateShotClipModel = SettingsField( default_factory=CreateShotClipModel, title="Create Shot Clip" ) diff --git a/server_addon/flame/server/settings/imageio.py b/server_addon/flame/server/settings/imageio.py index ef1e4721d1..3f6ec31ef4 100644 --- a/server_addon/flame/server/settings/imageio.py +++ b/server_addon/flame/server/settings/imageio.py @@ -1,17 +1,21 @@ -from pydantic import Field, validator -from ayon_server.settings import BaseSettingsModel, ensure_unique_names +from pydantic import validator +from ayon_server.settings import ( + BaseSettingsModel, + SettingsField, + ensure_unique_names, +) class ImageIOFileRuleModel(BaseSettingsModel): - name: str = Field("", title="Rule name") - pattern: str = Field("", title="Regex pattern") - colorspace: str = Field("", title="Colorspace name") - ext: str = Field("", title="File extension") + name: str = SettingsField("", title="Rule name") + pattern: str = SettingsField("", title="Regex pattern") + colorspace: str = SettingsField("", title="Colorspace name") + ext: str = SettingsField("", title="File extension") class ImageIOFileRulesModel(BaseSettingsModel): - activate_host_rules: bool = Field(False) - rules: list[ImageIOFileRuleModel] = Field( + activate_host_rules: bool = SettingsField(False) + rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, title="Rules" ) @@ -23,24 +27,24 @@ class ImageIOFileRulesModel(BaseSettingsModel): class ImageIORemappingRulesModel(BaseSettingsModel): - host_native_name: str = Field( + host_native_name: str = SettingsField( title="Application native colorspace name" ) - ocio_name: str = Field(title="OCIO colorspace name") + ocio_name: str = SettingsField(title="OCIO colorspace name") class ImageIORemappingModel(BaseSettingsModel): - rules: list[ImageIORemappingRulesModel] = Field( + rules: list[ImageIORemappingRulesModel] = SettingsField( default_factory=list ) class ImageIOConfigModel(BaseSettingsModel): - override_global_config: bool = Field( + override_global_config: bool = SettingsField( False, title="Override global OCIO config" ) - filepath: list[str] = Field( + filepath: list[str] = SettingsField( default_factory=list, title="Config path" ) @@ -49,30 +53,30 @@ class ImageIOConfigModel(BaseSettingsModel): class ProfileNamesMappingInputsModel(BaseSettingsModel): _layout = "expanded" - flameName: str = Field("", title="Flame name") - ocioName: str = Field("", title="OCIO name") + flameName: str = SettingsField("", title="Flame name") + ocioName: str = SettingsField("", title="OCIO name") class ProfileNamesMappingModel(BaseSettingsModel): _layout = "expanded" - inputs: list[ProfileNamesMappingInputsModel] = Field( + inputs: list[ProfileNamesMappingInputsModel] = SettingsField( default_factory=list, title="Profile names mapping" ) class ImageIOProjectModel(BaseSettingsModel): - colourPolicy: str = Field( + colourPolicy: str = SettingsField( "ACES 1.1", title="Colour Policy (name or path)", section="Project" ) - frameDepth: str = Field( + frameDepth: str = SettingsField( "16-bit fp", title="Image Depth" ) - fieldDominance: str = Field( + fieldDominance: str = SettingsField( "PROGRESSIVE", title="Field Dominance" ) @@ -80,18 +84,18 @@ class ImageIOProjectModel(BaseSettingsModel): class FlameImageIOModel(BaseSettingsModel): _isGroup = True - activate_host_color_management: bool = Field( + activate_host_color_management: bool = SettingsField( True, title="Enable Color Management" ) - remapping: ImageIORemappingModel = Field( + remapping: ImageIORemappingModel = SettingsField( title="Remapping colorspace names", default_factory=ImageIORemappingModel ) - ocio_config: ImageIOConfigModel = Field( + ocio_config: ImageIOConfigModel = SettingsField( default_factory=ImageIOConfigModel, title="OCIO config" ) - file_rules: ImageIOFileRulesModel = Field( + file_rules: ImageIOFileRulesModel = SettingsField( default_factory=ImageIOFileRulesModel, title="File Rules" ) @@ -99,11 +103,11 @@ class FlameImageIOModel(BaseSettingsModel): # inconsistency with v3 settings and harder conversion handling # - it can be moved back but keep in mind that it must be handled in v3 # conversion script too - project: ImageIOProjectModel = Field( + project: ImageIOProjectModel = SettingsField( default_factory=ImageIOProjectModel, title="Project" ) - profilesMapping: ProfileNamesMappingModel = Field( + profilesMapping: ProfileNamesMappingModel = SettingsField( default_factory=ProfileNamesMappingModel, title="Profile names mapping" ) diff --git a/server_addon/flame/server/settings/loader_plugins.py b/server_addon/flame/server/settings/loader_plugins.py index 6c27b926c2..e616f442b5 100644 --- a/server_addon/flame/server/settings/loader_plugins.py +++ b/server_addon/flame/server/settings/loader_plugins.py @@ -1,60 +1,64 @@ -from ayon_server.settings import Field, BaseSettingsModel +from ayon_server.settings import SettingsField, BaseSettingsModel class LoadClipModel(BaseSettingsModel): - enabled: bool = Field(True) + enabled: bool = SettingsField(True) - product_types: list[str] = Field( + product_types: list[str] = SettingsField( default_factory=list, title="Product types" ) - reel_group_name: str = Field( + reel_group_name: str = SettingsField( "OpenPype_Reels", title="Reel group name" ) - reel_name: str = Field( + reel_name: str = SettingsField( "Loaded", title="Reel name" ) - clip_name_template: str = Field( + clip_name_template: str = SettingsField( "{folder[name]}_{product[name]}<_{output}>", title="Clip name template" ) - layer_rename_template: str = Field("", title="Layer name template") - layer_rename_patterns: list[str] = Field( + layer_rename_template: str = SettingsField( + "", title="Layer name template" + ) + layer_rename_patterns: list[str] = SettingsField( default_factory=list, title="Layer rename patters", ) class LoadClipBatchModel(BaseSettingsModel): - enabled: bool = Field(True) - product_types: list[str] = Field( + enabled: bool = SettingsField(True) + product_types: list[str] = SettingsField( default_factory=list, title="Product types" ) - reel_name: str = Field( + reel_name: str = SettingsField( "OP_LoadedReel", title="Reel name" ) - clip_name_template: str = Field( + clip_name_template: str = SettingsField( "{batch}_{folder[name]}_{product[name]}<_{output}>", title="Clip name template" ) - layer_rename_template: str = Field("", title="Layer name template") - layer_rename_patterns: list[str] = Field( + layer_rename_template: str = SettingsField( + "", title="Layer name template" + ) + layer_rename_patterns: list[str] = SettingsField( default_factory=list, title="Layer rename patters", ) class LoaderPluginsModel(BaseSettingsModel): - LoadClip: LoadClipModel = Field( + LoadClip: LoadClipModel = SettingsField( default_factory=LoadClipModel, title="Load Clip" ) - LoadClipBatch: LoadClipBatchModel = Field( + LoadClipBatch: LoadClipBatchModel = SettingsField( default_factory=LoadClipBatchModel, title="Load as clip to current batch" ) diff --git a/server_addon/flame/server/settings/main.py b/server_addon/flame/server/settings/main.py index f28de6641b..047f5af287 100644 --- a/server_addon/flame/server/settings/main.py +++ b/server_addon/flame/server/settings/main.py @@ -1,4 +1,4 @@ -from ayon_server.settings import Field, BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField from .imageio import FlameImageIOModel, DEFAULT_IMAGEIO_SETTINGS from .create_plugins import CreatePuginsModel, DEFAULT_CREATE_SETTINGS @@ -7,19 +7,19 @@ from .loader_plugins import LoaderPluginsModel, DEFAULT_LOADER_SETTINGS class FlameSettings(BaseSettingsModel): - imageio: FlameImageIOModel = Field( + imageio: FlameImageIOModel = SettingsField( default_factory=FlameImageIOModel, title="Color Management (ImageIO)" ) - create: CreatePuginsModel = Field( + create: CreatePuginsModel = SettingsField( default_factory=CreatePuginsModel, title="Create plugins" ) - publish: PublishPuginsModel = Field( + publish: PublishPuginsModel = SettingsField( default_factory=PublishPuginsModel, title="Publish plugins" ) - load: LoaderPluginsModel = Field( + load: LoaderPluginsModel = SettingsField( default_factory=LoaderPluginsModel, title="Loader plugins" ) diff --git a/server_addon/flame/server/settings/publish_plugins.py b/server_addon/flame/server/settings/publish_plugins.py index ea7f109f73..decb00fcfa 100644 --- a/server_addon/flame/server/settings/publish_plugins.py +++ b/server_addon/flame/server/settings/publish_plugins.py @@ -1,10 +1,14 @@ -from ayon_server.settings import Field, BaseSettingsModel, task_types_enum +from ayon_server.settings import ( + BaseSettingsModel, + SettingsField, + task_types_enum, +) class XMLPresetAttrsFromCommentsModel(BaseSettingsModel): _layout = "expanded" - name: str = Field("", title="Attribute name") - type: str = Field( + name: str = SettingsField("", title="Attribute name") + type: str = SettingsField( default_factory=str, title="Attribute type", enum_resolver=lambda: ["number", "float", "string"] @@ -13,13 +17,13 @@ class XMLPresetAttrsFromCommentsModel(BaseSettingsModel): class AddTasksModel(BaseSettingsModel): _layout = "expanded" - name: str = Field("", title="Task name") - type: str = Field( + name: str = SettingsField("", title="Task name") + type: str = SettingsField( default_factory=str, title="Task type", enum_resolver=task_types_enum ) - create_batch_group: bool = Field( + create_batch_group: bool = SettingsField( True, title="Create batch group" ) @@ -28,11 +32,13 @@ class AddTasksModel(BaseSettingsModel): class CollectTimelineInstancesModel(BaseSettingsModel): _isGroup = True - xml_preset_attrs_from_comments: list[XMLPresetAttrsFromCommentsModel] = Field( - default_factory=list, - title="XML presets attributes parsable from segment comments" + xml_preset_attrs_from_comments: list[XMLPresetAttrsFromCommentsModel] = ( + SettingsField( + default_factory=list, + title="XML presets attributes parsable from segment comments" + ) ) - add_tasks: list[AddTasksModel] = Field( + add_tasks: list[AddTasksModel] = SettingsField( default_factory=list, title="Add tasks" ) @@ -41,22 +47,22 @@ class CollectTimelineInstancesModel(BaseSettingsModel): class ExportPresetsMappingModel(BaseSettingsModel): _layout = "expanded" - name: str = Field( + name: str = SettingsField( ..., title="Name" ) - active: bool = Field(True, title="Is active") - export_type: str = Field( + active: bool = SettingsField(True, title="Is active") + export_type: str = SettingsField( "File Sequence", title="Eport clip type", enum_resolver=lambda: ["Movie", "File Sequence", "Sequence Publish"] ) - ext: str = Field("exr", title="Output extension") - xml_preset_file: str = Field( + ext: str = SettingsField("exr", title="Output extension") + xml_preset_file: str = SettingsField( "OpenEXR (16-bit fp DWAA).xml", title="XML preset file (with ext)" ) - colorspace_out: str = Field( + colorspace_out: str = SettingsField( "ACES - ACEScg", title="Output color (imageio)" ) @@ -65,31 +71,31 @@ class ExportPresetsMappingModel(BaseSettingsModel): # created inconsistency with v3 settings and harder conversion handling # - it can be moved back but keep in mind that it must be handled in v3 # conversion script too - xml_preset_dir: str = Field( + xml_preset_dir: str = SettingsField( "", title="XML preset directory" ) - parsed_comment_attrs: bool = Field( + parsed_comment_attrs: bool = SettingsField( True, title="Parsed comment attributes" ) - representation_add_range: bool = Field( + representation_add_range: bool = SettingsField( True, title="Add range to representation name" ) - representation_tags: list[str] = Field( + representation_tags: list[str] = SettingsField( default_factory=list, title="Representation tags" ) - load_to_batch_group: bool = Field( + load_to_batch_group: bool = SettingsField( True, title="Load to batch group reel" ) - batch_group_loader_name: str = Field( + batch_group_loader_name: str = SettingsField( "LoadClipBatch", title="Use loader name" ) - filter_path_regex: str = Field( + filter_path_regex: str = SettingsField( ".*", title="Regex in clip path" ) @@ -98,35 +104,35 @@ class ExportPresetsMappingModel(BaseSettingsModel): class ExtractProductResourcesModel(BaseSettingsModel): _isGroup = True - keep_original_representation: bool = Field( + keep_original_representation: bool = SettingsField( False, title="Publish clip's original media" ) - export_presets_mapping: list[ExportPresetsMappingModel] = Field( + export_presets_mapping: list[ExportPresetsMappingModel] = SettingsField( default_factory=list, title="Export presets mapping" ) class IntegrateBatchGroupModel(BaseSettingsModel): - enabled: bool = Field( + enabled: bool = SettingsField( False, title="Enabled" ) class PublishPuginsModel(BaseSettingsModel): - CollectTimelineInstances: CollectTimelineInstancesModel = Field( + CollectTimelineInstances: CollectTimelineInstancesModel = SettingsField( default_factory=CollectTimelineInstancesModel, title="Collect Timeline Instances" ) - ExtractProductResources: ExtractProductResourcesModel = Field( + ExtractProductResources: ExtractProductResourcesModel = SettingsField( default_factory=ExtractProductResourcesModel, title="Extract Product Resources" ) - IntegrateBatchGroup: IntegrateBatchGroupModel = Field( + IntegrateBatchGroup: IntegrateBatchGroupModel = SettingsField( default_factory=IntegrateBatchGroupModel, title="IntegrateBatchGroup" ) diff --git a/server_addon/fusion/server/imageio.py b/server_addon/fusion/server/imageio.py index fe867af424..e93dc2ae00 100644 --- a/server_addon/fusion/server/imageio.py +++ b/server_addon/fusion/server/imageio.py @@ -1,29 +1,29 @@ -from pydantic import Field, validator -from ayon_server.settings import BaseSettingsModel +from pydantic import validator +from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.settings.validators import ensure_unique_names class ImageIOConfigModel(BaseSettingsModel): - override_global_config: bool = Field( + override_global_config: bool = SettingsField( False, title="Override global OCIO config" ) - filepath: list[str] = Field( + filepath: list[str] = SettingsField( default_factory=list, title="Config path" ) class ImageIOFileRuleModel(BaseSettingsModel): - name: str = Field("", title="Rule name") - pattern: str = Field("", title="Regex pattern") - colorspace: str = Field("", title="Colorspace name") - ext: str = Field("", title="File extension") + name: str = SettingsField("", title="Rule name") + pattern: str = SettingsField("", title="Regex pattern") + colorspace: str = SettingsField("", title="Colorspace name") + ext: str = SettingsField("", title="File extension") class ImageIOFileRulesModel(BaseSettingsModel): - activate_host_rules: bool = Field(False) - rules: list[ImageIOFileRuleModel] = Field( + activate_host_rules: bool = SettingsField(False) + rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, title="Rules" ) @@ -35,14 +35,14 @@ class ImageIOFileRulesModel(BaseSettingsModel): class FusionImageIOModel(BaseSettingsModel): - activate_host_color_management: bool = Field( + activate_host_color_management: bool = SettingsField( True, title="Enable Color Management" ) - ocio_config: ImageIOConfigModel = Field( + ocio_config: ImageIOConfigModel = SettingsField( default_factory=ImageIOConfigModel, title="OCIO config" ) - file_rules: ImageIOFileRulesModel = Field( + file_rules: ImageIOFileRulesModel = SettingsField( default_factory=ImageIOFileRulesModel, title="File Rules" ) diff --git a/server_addon/fusion/server/settings.py b/server_addon/fusion/server/settings.py index bf295f3064..b157ce9e40 100644 --- a/server_addon/fusion/server/settings.py +++ b/server_addon/fusion/server/settings.py @@ -1,15 +1,15 @@ -from pydantic import Field from ayon_server.settings import ( BaseSettingsModel, + SettingsField, ) from .imageio import FusionImageIOModel class CopyFusionSettingsModel(BaseSettingsModel): - copy_path: str = Field("", title="Local Fusion profile directory") - copy_status: bool = Field(title="Copy profile on first launch") - force_sync: bool = Field(title="Resync profile on each launch") + copy_path: str = SettingsField("", title="Local Fusion profile directory") + copy_status: bool = SettingsField(title="Copy profile on first launch") + force_sync: bool = SettingsField(title="Resync profile on each launch") def _create_saver_instance_attributes_enum(): @@ -45,40 +45,40 @@ def _frame_range_options_enum(): class CreateSaverPluginModel(BaseSettingsModel): _isGroup = True - temp_rendering_path_template: str = Field( + temp_rendering_path_template: str = SettingsField( "", title="Temporary rendering path template" ) - default_variants: list[str] = Field( + default_variants: list[str] = SettingsField( default_factory=list, title="Default variants" ) - instance_attributes: list[str] = Field( + instance_attributes: list[str] = SettingsField( default_factory=list, enum_resolver=_create_saver_instance_attributes_enum, title="Instance attributes" ) - output_formats: list[str] = Field( + output_formats: list[str] = SettingsField( default_factory=list, title="Output formats" ) class HookOptionalModel(BaseSettingsModel): - enabled: bool = Field( + enabled: bool = SettingsField( True, title="Enabled" ) class HooksModel(BaseSettingsModel): - InstallPySideToFusion: HookOptionalModel = Field( + InstallPySideToFusion: HookOptionalModel = SettingsField( default_factory=HookOptionalModel, title="Install PySide2" ) class CreateSaverModel(CreateSaverPluginModel): - default_frame_range_option: str = Field( + default_frame_range_option: str = SettingsField( default="asset_db", enum_resolver=_frame_range_options_enum, title="Default frame range source" @@ -86,17 +86,17 @@ class CreateSaverModel(CreateSaverPluginModel): class CreateImageSaverModel(CreateSaverPluginModel): - default_frame: int = Field( + default_frame: int = SettingsField( 0, title="Default rendered frame" ) class CreatPluginsModel(BaseSettingsModel): - CreateSaver: CreateSaverModel = Field( + CreateSaver: CreateSaverModel = SettingsField( default_factory=CreateSaverModel, title="Create Saver", description="Creator for render product type (eg. sequence)" ) - CreateImageSaver: CreateImageSaverModel = Field( + CreateImageSaver: CreateImageSaverModel = SettingsField( default_factory=CreateImageSaverModel, title="Create Image Saver", description="Creator for image product type (eg. single)" @@ -104,19 +104,19 @@ class CreatPluginsModel(BaseSettingsModel): class FusionSettings(BaseSettingsModel): - imageio: FusionImageIOModel = Field( + imageio: FusionImageIOModel = SettingsField( default_factory=FusionImageIOModel, title="Color Management (ImageIO)" ) - copy_fusion_settings: CopyFusionSettingsModel = Field( + copy_fusion_settings: CopyFusionSettingsModel = SettingsField( default_factory=CopyFusionSettingsModel, title="Local Fusion profile settings" ) - hooks: HooksModel = Field( + hooks: HooksModel = SettingsField( default_factory=HooksModel, title="Hooks" ) - create: CreatPluginsModel = Field( + create: CreatPluginsModel = SettingsField( default_factory=CreatPluginsModel, title="Creator plugins" ) diff --git a/server_addon/harmony/server/settings/imageio.py b/server_addon/harmony/server/settings/imageio.py index 4e01fae3d4..a4b481f91f 100644 --- a/server_addon/harmony/server/settings/imageio.py +++ b/server_addon/harmony/server/settings/imageio.py @@ -1,29 +1,29 @@ -from pydantic import Field, validator -from ayon_server.settings import BaseSettingsModel +from pydantic import validator +from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.settings.validators import ensure_unique_names class ImageIOConfigModel(BaseSettingsModel): - override_global_config: bool = Field( + override_global_config: bool = SettingsField( False, title="Override global OCIO config" ) - filepath: list[str] = Field( + filepath: list[str] = SettingsField( default_factory=list, title="Config path" ) class ImageIOFileRuleModel(BaseSettingsModel): - name: str = Field("", title="Rule name") - pattern: str = Field("", title="Regex pattern") - colorspace: str = Field("", title="Colorspace name") - ext: str = Field("", title="File extension") + name: str = SettingsField("", title="Rule name") + pattern: str = SettingsField("", title="Regex pattern") + colorspace: str = SettingsField("", title="Colorspace name") + ext: str = SettingsField("", title="File extension") class ImageIOFileRulesModel(BaseSettingsModel): - activate_host_rules: bool = Field(False) - rules: list[ImageIOFileRuleModel] = Field( + activate_host_rules: bool = SettingsField(False) + rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, title="Rules" ) @@ -35,21 +35,21 @@ class ImageIOFileRulesModel(BaseSettingsModel): class ImageIORemappingRulesModel(BaseSettingsModel): - host_native_name: str = Field( + host_native_name: str = SettingsField( title="Application native colorspace name" ) - ocio_name: str = Field(title="OCIO colorspace name") + ocio_name: str = SettingsField(title="OCIO colorspace name") class HarmonyImageIOModel(BaseSettingsModel): - activate_host_color_management: bool = Field( + activate_host_color_management: bool = SettingsField( True, title="Enable Color Management" ) - ocio_config: ImageIOConfigModel = Field( + ocio_config: ImageIOConfigModel = SettingsField( default_factory=ImageIOConfigModel, title="OCIO config" ) - file_rules: ImageIOFileRulesModel = Field( + file_rules: ImageIOFileRulesModel = SettingsField( default_factory=ImageIOFileRulesModel, title="File Rules" ) diff --git a/server_addon/harmony/server/settings/main.py b/server_addon/harmony/server/settings/main.py index 0936bc1fc7..9c780b63c2 100644 --- a/server_addon/harmony/server/settings/main.py +++ b/server_addon/harmony/server/settings/main.py @@ -1,5 +1,4 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField from .imageio import HarmonyImageIOModel from .publish_plugins import HarmonyPublishPlugins @@ -8,11 +7,11 @@ from .publish_plugins import HarmonyPublishPlugins class HarmonySettings(BaseSettingsModel): """Harmony Project Settings.""" - imageio: HarmonyImageIOModel = Field( + imageio: HarmonyImageIOModel = SettingsField( default_factory=HarmonyImageIOModel, title="OCIO config" ) - publish: HarmonyPublishPlugins = Field( + publish: HarmonyPublishPlugins = SettingsField( default_factory=HarmonyPublishPlugins, title="Publish plugins" ) diff --git a/server_addon/harmony/server/settings/publish_plugins.py b/server_addon/harmony/server/settings/publish_plugins.py index bdaec2bbd4..c9e7c515e4 100644 --- a/server_addon/harmony/server/settings/publish_plugins.py +++ b/server_addon/harmony/server/settings/publish_plugins.py @@ -1,12 +1,10 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class CollectPalettesPlugin(BaseSettingsModel): """Set regular expressions to filter triggering on specific task names. '.*' means on all.""" # noqa - allowed_tasks: list[str] = Field( + allowed_tasks: list[str] = SettingsField( default_factory=list, title="Allowed tasks" ) @@ -16,16 +14,16 @@ class ValidateAudioPlugin(BaseSettingsModel): """Check if scene contains audio track.""" # _isGroup = True enabled: bool = True - optional: bool = Field(False, title="Optional") - active: bool = Field(True, title="Active") + optional: bool = SettingsField(False, title="Optional") + active: bool = SettingsField(True, title="Active") class ValidateContainersPlugin(BaseSettingsModel): """Check if loaded container is scene are latest versions.""" _isGroup = True enabled: bool = True - optional: bool = Field(False, title="Optional") - active: bool = Field(True, title="Active") + optional: bool = SettingsField(False, title="Optional") + active: bool = SettingsField(True, title="Active") class ValidateSceneSettingsPlugin(BaseSettingsModel): @@ -34,20 +32,20 @@ class ValidateSceneSettingsPlugin(BaseSettingsModel): or task names.""" _isGroup = True enabled: bool = True - optional: bool = Field(False, title="Optional") - active: bool = Field(True, title="Active") + optional: bool = SettingsField(False, title="Optional") + active: bool = SettingsField(True, title="Active") - frame_check_filter: list[str] = Field( + frame_check_filter: list[str] = SettingsField( default_factory=list, title="Skip Frame check for Assets with name containing" ) - skip_resolution_check: list[str] = Field( + skip_resolution_check: list[str] = SettingsField( default_factory=list, title="Skip Resolution Check for Tasks" ) - skip_timelines_check: list[str] = Field( + skip_timelines_check: list[str] = SettingsField( default_factory=list, title="Skip Timeline Check for Tasks" ) @@ -55,22 +53,22 @@ class ValidateSceneSettingsPlugin(BaseSettingsModel): class HarmonyPublishPlugins(BaseSettingsModel): - CollectPalettes: CollectPalettesPlugin = Field( + CollectPalettes: CollectPalettesPlugin = SettingsField( title="Collect Palettes", default_factory=CollectPalettesPlugin, ) - ValidateAudio: ValidateAudioPlugin = Field( + ValidateAudio: ValidateAudioPlugin = SettingsField( title="Validate Audio", default_factory=ValidateAudioPlugin, ) - ValidateContainers: ValidateContainersPlugin = Field( + ValidateContainers: ValidateContainersPlugin = SettingsField( title="Validate Containers", default_factory=ValidateContainersPlugin, ) - ValidateSceneSettings: ValidateSceneSettingsPlugin = Field( + ValidateSceneSettings: ValidateSceneSettingsPlugin = SettingsField( title="Validate Scene Settings", default_factory=ValidateSceneSettingsPlugin, ) diff --git a/server_addon/hiero/server/settings/common.py b/server_addon/hiero/server/settings/common.py index eb4791f93e..7b5e4390c5 100644 --- a/server_addon/hiero/server/settings/common.py +++ b/server_addon/hiero/server/settings/common.py @@ -1,5 +1,4 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.types import ( ColorRGBA_float, ColorRGB_uint8 @@ -9,16 +8,16 @@ from ayon_server.types import ( class Vector2d(BaseSettingsModel): _layout = "compact" - x: float = Field(1.0, title="X") - y: float = Field(1.0, title="Y") + x: float = SettingsField(1.0, title="X") + y: float = SettingsField(1.0, title="Y") class Vector3d(BaseSettingsModel): _layout = "compact" - x: float = Field(1.0, title="X") - y: float = Field(1.0, title="Y") - z: float = Field(1.0, title="Z") + x: float = SettingsField(1.0, title="X") + y: float = SettingsField(1.0, title="Y") + z: float = SettingsField(1.0, title="Z") def formatable_knob_type_enum(): @@ -34,12 +33,12 @@ def formatable_knob_type_enum(): class Formatable(BaseSettingsModel): _layout = "compact" - template: str = Field( + template: str = SettingsField( "", placeholder="""{{key}} or {{key}};{{key}}""", title="Template" ) - to_type: str = Field( + to_type: str = SettingsField( "Text", title="To Knob type", enum_resolver=formatable_knob_type_enum, @@ -62,37 +61,37 @@ knob_types_enum = [ class KnobModel(BaseSettingsModel): _layout = "expanded" - type: str = Field( + type: str = SettingsField( title="Type", description="Switch between different knob types", enum_resolver=lambda: knob_types_enum, conditionalEnum=True ) - name: str = Field( + name: str = SettingsField( title="Name", placeholder="Name" ) - text: str = Field("", title="Value") - color_gui: ColorRGB_uint8 = Field( + text: str = SettingsField("", title="Value") + color_gui: ColorRGB_uint8 = SettingsField( (0, 0, 255), title="RGB Uint8", ) - boolean: bool = Field(False, title="Value") - number: int = Field(0, title="Value") - decimal_number: float = Field(0.0, title="Value") - vector_2d: Vector2d = Field( + boolean: bool = SettingsField(False, title="Value") + number: int = SettingsField(0, title="Value") + decimal_number: float = SettingsField(0.0, title="Value") + vector_2d: Vector2d = SettingsField( default_factory=Vector2d, title="Value" ) - vector_3d: Vector3d = Field( + vector_3d: Vector3d = SettingsField( default_factory=Vector3d, title="Value" ) - color: ColorRGBA_float = Field( + color: ColorRGBA_float = SettingsField( (0.0, 0.0, 1.0, 1.0), title="RGBA Float" ) - formatable: Formatable = Field( + formatable: Formatable = SettingsField( default_factory=Formatable, title="Value" ) diff --git a/server_addon/hiero/server/settings/create_plugins.py b/server_addon/hiero/server/settings/create_plugins.py index daec4a7cea..80e0b67182 100644 --- a/server_addon/hiero/server/settings/create_plugins.py +++ b/server_addon/hiero/server/settings/create_plugins.py @@ -1,75 +1,74 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class CreateShotClipModels(BaseSettingsModel): - hierarchy: str = Field( + hierarchy: str = SettingsField( "{folder}/{sequence}", title="Shot parent hierarchy", section="Shot Hierarchy And Rename Settings" ) - clipRename: bool = Field( + clipRename: bool = SettingsField( True, title="Rename clips" ) - clipName: str = Field( + clipName: str = SettingsField( "{track}{sequence}{shot}", title="Clip name template" ) - countFrom: int = Field( + countFrom: int = SettingsField( 10, title="Count sequence from" ) - countSteps: int = Field( + countSteps: int = SettingsField( 10, title="Stepping number" ) - folder: str = Field( + folder: str = SettingsField( "shots", title="{folder}", section="Shot Template Keywords" ) - episode: str = Field( + episode: str = SettingsField( "ep01", title="{episode}" ) - sequence: str = Field( + sequence: str = SettingsField( "sq01", title="{sequence}" ) - track: str = Field( + track: str = SettingsField( "{_track_}", title="{track}" ) - shot: str = Field( + shot: str = SettingsField( "sh###", title="{shot}" ) - vSyncOn: bool = Field( + vSyncOn: bool = SettingsField( False, title="Enable Vertical Sync", section="Vertical Synchronization Of Attributes" ) - workfileFrameStart: int = Field( + workfileFrameStart: int = SettingsField( 1001, title="Workfiles Start Frame", section="Shot Attributes" ) - handleStart: int = Field( + handleStart: int = SettingsField( 10, title="Handle start (head)" ) - handleEnd: int = Field( + handleEnd: int = SettingsField( 10, title="Handle end (tail)" ) class CreatorPluginsSettings(BaseSettingsModel): - CreateShotClip: CreateShotClipModels = Field( + CreateShotClip: CreateShotClipModels = SettingsField( default_factory=CreateShotClipModels, title="Create Shot Clip" ) diff --git a/server_addon/hiero/server/settings/filters.py b/server_addon/hiero/server/settings/filters.py index 7e2702b3b7..095d30a004 100644 --- a/server_addon/hiero/server/settings/filters.py +++ b/server_addon/hiero/server/settings/filters.py @@ -1,17 +1,23 @@ -from pydantic import Field, validator -from ayon_server.settings import BaseSettingsModel, ensure_unique_names +from pydantic import validator +from ayon_server.settings import ( + BaseSettingsModel, + SettingsField, + ensure_unique_names, +) class PublishGUIFilterItemModel(BaseSettingsModel): _layout = "compact" - name: str = Field(title="Name") - value: bool = Field(True, title="Active") + name: str = SettingsField(title="Name") + value: bool = SettingsField(True, title="Active") class PublishGUIFiltersModel(BaseSettingsModel): _layout = "compact" - name: str = Field(title="Name") - value: list[PublishGUIFilterItemModel] = Field(default_factory=list) + name: str = SettingsField(title="Name") + value: list[PublishGUIFilterItemModel] = SettingsField( + default_factory=list + ) @validator("value") def validate_unique_outputs(cls, value): diff --git a/server_addon/hiero/server/settings/imageio.py b/server_addon/hiero/server/settings/imageio.py index f2c2728057..f2bc71ac33 100644 --- a/server_addon/hiero/server/settings/imageio.py +++ b/server_addon/hiero/server/settings/imageio.py @@ -1,7 +1,8 @@ -from pydantic import Field, validator +from pydantic import validator from ayon_server.settings import ( BaseSettingsModel, + SettingsField, ensure_unique_names, ) @@ -39,34 +40,34 @@ class WorkfileColorspaceSettings(BaseSettingsModel): thumbnail_name = thumbnailLut """ - ocioConfigName: str = Field( + ocioConfigName: str = SettingsField( title="OpenColorIO Config", description="Switch between OCIO configs", enum_resolver=ocio_configs_switcher_enum, conditionalEnum=True ) - workingSpace: str = Field( + workingSpace: str = SettingsField( title="Working Space" ) - viewerLut: str = Field( + viewerLut: str = SettingsField( title="Viewer" ) - eightBitLut: str = Field( + eightBitLut: str = SettingsField( title="8-bit files" ) - sixteenBitLut: str = Field( + sixteenBitLut: str = SettingsField( title="16-bit files" ) - logLut: str = Field( + logLut: str = SettingsField( title="Log files" ) - floatLut: str = Field( + floatLut: str = SettingsField( title="Float files" ) - thumbnailLut: str = Field( + thumbnailLut: str = SettingsField( title="Thumnails" ) - monitorOutLut: str = Field( + monitorOutLut: str = SettingsField( title="Monitor" ) @@ -74,38 +75,38 @@ class WorkfileColorspaceSettings(BaseSettingsModel): class ClipColorspaceRulesItems(BaseSettingsModel): _layout = "expanded" - regex: str = Field("", title="Regex expression") - colorspace: str = Field("", title="Colorspace") + regex: str = SettingsField("", title="Regex expression") + colorspace: str = SettingsField("", title="Colorspace") class RegexInputsModel(BaseSettingsModel): - inputs: list[ClipColorspaceRulesItems] = Field( + inputs: list[ClipColorspaceRulesItems] = SettingsField( default_factory=list, title="Inputs" ) class ImageIOConfigModel(BaseSettingsModel): - override_global_config: bool = Field( + override_global_config: bool = SettingsField( False, title="Override global OCIO config" ) - filepath: list[str] = Field( + filepath: list[str] = SettingsField( default_factory=list, title="Config path" ) class ImageIOFileRuleModel(BaseSettingsModel): - name: str = Field("", title="Rule name") - pattern: str = Field("", title="Regex pattern") - colorspace: str = Field("", title="Colorspace name") - ext: str = Field("", title="File extension") + name: str = SettingsField("", title="Rule name") + pattern: str = SettingsField("", title="Regex pattern") + colorspace: str = SettingsField("", title="Colorspace name") + ext: str = SettingsField("", title="File extension") class ImageIOFileRulesModel(BaseSettingsModel): - activate_host_rules: bool = Field(False) - rules: list[ImageIOFileRuleModel] = Field( + activate_host_rules: bool = SettingsField(False) + rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, title="Rules" ) @@ -119,18 +120,18 @@ class ImageIOFileRulesModel(BaseSettingsModel): class ImageIOSettings(BaseSettingsModel): """Hiero color management project settings. """ _isGroup: bool = True - activate_host_color_management: bool = Field( + activate_host_color_management: bool = SettingsField( True, title="Enable Color Management" ) - ocio_config: ImageIOConfigModel = Field( + ocio_config: ImageIOConfigModel = SettingsField( default_factory=ImageIOConfigModel, title="OCIO config" ) - file_rules: ImageIOFileRulesModel = Field( + file_rules: ImageIOFileRulesModel = SettingsField( default_factory=ImageIOFileRulesModel, title="File Rules" ) - workfile: WorkfileColorspaceSettings = Field( + workfile: WorkfileColorspaceSettings = SettingsField( default_factory=WorkfileColorspaceSettings, title="Workfile" ) @@ -140,7 +141,7 @@ class ImageIOSettings(BaseSettingsModel): - no need for `inputs` middle part. It can stay directly on `regex_inputs` """ - regexInputs: RegexInputsModel = Field( + regexInputs: RegexInputsModel = SettingsField( default_factory=RegexInputsModel, title="Assign colorspace to clips via rules" ) diff --git a/server_addon/hiero/server/settings/loader_plugins.py b/server_addon/hiero/server/settings/loader_plugins.py index 83b3564c2a..b5a81d1ae2 100644 --- a/server_addon/hiero/server/settings/loader_plugins.py +++ b/server_addon/hiero/server/settings/loader_plugins.py @@ -1,23 +1,22 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class LoadClipModel(BaseSettingsModel): - enabled: bool = Field( + enabled: bool = SettingsField( True, title="Enabled" ) - product_types: list[str] = Field( + product_types: list[str] = SettingsField( default_factory=list, title="Product types" ) - clip_name_template: str = Field( + clip_name_template: str = SettingsField( title="Clip name template" ) class LoaderPuginsModel(BaseSettingsModel): - LoadClip: LoadClipModel = Field( + LoadClip: LoadClipModel = SettingsField( default_factory=LoadClipModel, title="Load Clip" ) diff --git a/server_addon/hiero/server/settings/main.py b/server_addon/hiero/server/settings/main.py index 47f8110c22..b170ecafb8 100644 --- a/server_addon/hiero/server/settings/main.py +++ b/server_addon/hiero/server/settings/main.py @@ -1,6 +1,4 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField from .imageio import ( ImageIOSettings, @@ -28,28 +26,28 @@ from .filters import PublishGUIFilterItemModel class HieroSettings(BaseSettingsModel): """Nuke addon settings.""" - imageio: ImageIOSettings = Field( + imageio: ImageIOSettings = SettingsField( default_factory=ImageIOSettings, title="Color Management (imageio)", ) - create: CreatorPluginsSettings = Field( + create: CreatorPluginsSettings = SettingsField( default_factory=CreatorPluginsSettings, title="Creator Plugins", ) - load: LoaderPuginsModel = Field( + load: LoaderPuginsModel = SettingsField( default_factory=LoaderPuginsModel, title="Loader plugins" ) - publish: PublishPuginsModel = Field( + publish: PublishPuginsModel = SettingsField( default_factory=PublishPuginsModel, title="Publish plugins" ) - scriptsmenu: ScriptsmenuSettings = Field( + scriptsmenu: ScriptsmenuSettings = SettingsField( default_factory=ScriptsmenuSettings, title="Scripts Menu Definition", ) - filters: list[PublishGUIFilterItemModel] = Field( + filters: list[PublishGUIFilterItemModel] = SettingsField( default_factory=list ) diff --git a/server_addon/hiero/server/settings/publish_plugins.py b/server_addon/hiero/server/settings/publish_plugins.py index a85e62724b..c35c61c332 100644 --- a/server_addon/hiero/server/settings/publish_plugins.py +++ b/server_addon/hiero/server/settings/publish_plugins.py @@ -1,35 +1,68 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from pydantic import validator +from ayon_server.settings import ( + BaseSettingsModel, + SettingsField, + ensure_unique_names, + normalize_name, +) class CollectInstanceVersionModel(BaseSettingsModel): - enabled: bool = Field( + enabled: bool = SettingsField( True, title="Enabled" ) +class CollectClipEffectsDefModel(BaseSettingsModel): + _layout = "expanded" + name: str = SettingsField("", title="Name") + effect_classes: list[str] = SettingsField( + default_factory=list, title="Effect Classes" + ) + + @validator("name") + def validate_name(cls, value): + """Ensure name does not contain weird characters""" + return normalize_name(value) + + +class CollectClipEffectsModel(BaseSettingsModel): + effect_categories: list[CollectClipEffectsDefModel] = SettingsField( + default_factory=list, title="Effect Categories" + ) + + @validator("effect_categories") + def validate_unique_outputs(cls, value): + ensure_unique_names(value) + return value + + class ExtractReviewCutUpVideoModel(BaseSettingsModel): - enabled: bool = Field( + enabled: bool = SettingsField( True, title="Enabled" ) - tags_addition: list[str] = Field( + tags_addition: list[str] = SettingsField( default_factory=list, title="Additional tags" ) class PublishPuginsModel(BaseSettingsModel): - CollectInstanceVersion: CollectInstanceVersionModel = Field( + CollectInstanceVersion: CollectInstanceVersionModel = SettingsField( default_factory=CollectInstanceVersionModel, title="Collect Instance Version" ) + CollectClipEffects: CollectClipEffectsModel = SettingsField( + default_factory=CollectClipEffectsModel, + title="Collect Clip Effects" + ) """# TODO: enhance settings with host api: Rename class name and plugin name to match title (it makes more sense) """ - ExtractReviewCutUpVideo: ExtractReviewCutUpVideoModel = Field( + ExtractReviewCutUpVideo: ExtractReviewCutUpVideoModel = SettingsField( default_factory=ExtractReviewCutUpVideoModel, title="Exctract Review Trim" ) @@ -44,5 +77,8 @@ DEFAULT_PUBLISH_PLUGIN_SETTINGS = { "tags_addition": [ "review" ] + }, + "CollectClipEffectsModel": { + "effect_categories": [] } } diff --git a/server_addon/hiero/server/settings/scriptsmenu.py b/server_addon/hiero/server/settings/scriptsmenu.py index ea898dd7ff..a627da9643 100644 --- a/server_addon/hiero/server/settings/scriptsmenu.py +++ b/server_addon/hiero/server/settings/scriptsmenu.py @@ -1,16 +1,15 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class ScriptsmenuSubmodel(BaseSettingsModel): """Item Definition""" _isGroup = True - type: str = Field(title="Type") - command: str = Field(title="Command") - sourcetype: str = Field(title="Source Type") - title: str = Field(title="Title") - tooltip: str = Field(title="Tooltip") + type: str = SettingsField(title="Type") + command: str = SettingsField(title="Command") + sourcetype: str = SettingsField(title="Source Type") + title: str = SettingsField(title="Title") + tooltip: str = SettingsField(title="Tooltip") class ScriptsmenuSettings(BaseSettingsModel): @@ -20,8 +19,8 @@ class ScriptsmenuSettings(BaseSettingsModel): """# TODO: enhance settings with host api: - in api rename key `name` to `menu_name` """ - name: str = Field(title="Menu name") - definition: list[ScriptsmenuSubmodel] = Field( + name: str = SettingsField(title="Menu name") + definition: list[ScriptsmenuSubmodel] = SettingsField( default_factory=list, title="Definition", description="Scriptmenu Items Definition") diff --git a/server_addon/hiero/server/version.py b/server_addon/hiero/server/version.py index 485f44ac21..b3f4756216 100644 --- a/server_addon/hiero/server/version.py +++ b/server_addon/hiero/server/version.py @@ -1 +1 @@ -__version__ = "0.1.1" +__version__ = "0.1.2" diff --git a/server_addon/houdini/server/settings/create.py b/server_addon/houdini/server/settings/create.py index a5ca4d477b..203ca4f9d6 100644 --- a/server_addon/houdini/server/settings/create.py +++ b/server_addon/houdini/server/settings/create.py @@ -1,92 +1,91 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField # Creator Plugins class CreatorModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - default_variants: list[str] = Field( + enabled: bool = SettingsField(title="Enabled") + default_variants: list[str] = SettingsField( title="Default Products", default_factory=list, ) class CreateArnoldAssModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - default_variants: list[str] = Field( + enabled: bool = SettingsField(title="Enabled") + default_variants: list[str] = SettingsField( title="Default Products", default_factory=list, ) - ext: str = Field(Title="Extension") + ext: str = SettingsField(Title="Extension") class CreateStaticMeshModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - default_variants: list[str] = Field( + enabled: bool = SettingsField(title="Enabled") + default_variants: list[str] = SettingsField( default_factory=list, title="Default Products" ) - static_mesh_prefix: str = Field("S", title="Static Mesh Prefix") - collision_prefixes: list[str] = Field( + static_mesh_prefix: str = SettingsField("S", title="Static Mesh Prefix") + collision_prefixes: list[str] = SettingsField( default_factory=list, title="Collision Prefixes" ) class CreatePluginsModel(BaseSettingsModel): - CreateAlembicCamera: CreatorModel = Field( + CreateAlembicCamera: CreatorModel = SettingsField( default_factory=CreatorModel, title="Create Alembic Camera") - CreateArnoldAss: CreateArnoldAssModel = Field( + CreateArnoldAss: CreateArnoldAssModel = SettingsField( default_factory=CreateArnoldAssModel, title="Create Arnold Ass") - CreateArnoldRop: CreatorModel = Field( + CreateArnoldRop: CreatorModel = SettingsField( default_factory=CreatorModel, title="Create Arnold ROP") - CreateCompositeSequence: CreatorModel = Field( + CreateCompositeSequence: CreatorModel = SettingsField( default_factory=CreatorModel, title="Create Composite (Image Sequence)") - CreateHDA: CreatorModel = Field( + CreateHDA: CreatorModel = SettingsField( default_factory=CreatorModel, title="Create Houdini Digital Asset") - CreateKarmaROP: CreatorModel = Field( + CreateKarmaROP: CreatorModel = SettingsField( default_factory=CreatorModel, title="Create Karma ROP") - CreateMantraIFD: CreatorModel = Field( + CreateMantraIFD: CreatorModel = SettingsField( default_factory=CreatorModel, title="Create Mantra IFD") - CreateMantraROP: CreatorModel = Field( + CreateMantraROP: CreatorModel = SettingsField( default_factory=CreatorModel, title="Create Mantra ROP") - CreatePointCache: CreatorModel = Field( + CreatePointCache: CreatorModel = SettingsField( default_factory=CreatorModel, title="Create PointCache (Abc)") - CreateBGEO: CreatorModel = Field( + CreateBGEO: CreatorModel = SettingsField( default_factory=CreatorModel, title="Create PointCache (Bgeo)") - CreateRedshiftProxy: CreatorModel = Field( + CreateRedshiftProxy: CreatorModel = SettingsField( default_factory=CreatorModel, title="Create Redshift Proxy") - CreateRedshiftROP: CreatorModel = Field( + CreateRedshiftROP: CreatorModel = SettingsField( default_factory=CreatorModel, title="Create Redshift ROP") - CreateReview: CreatorModel = Field( + CreateReview: CreatorModel = SettingsField( default_factory=CreatorModel, title="Create Review") # "-" is not compatible in the new model - CreateStaticMesh: CreateStaticMeshModel = Field( + CreateStaticMesh: CreateStaticMeshModel = SettingsField( default_factory=CreateStaticMeshModel, title="Create Static Mesh") - CreateUSD: CreatorModel = Field( + CreateUSD: CreatorModel = SettingsField( default_factory=CreatorModel, title="Create USD (experimental)") - CreateUSDRender: CreatorModel = Field( + CreateUSDRender: CreatorModel = SettingsField( default_factory=CreatorModel, title="Create USD render (experimental)") - CreateVDBCache: CreatorModel = Field( + CreateVDBCache: CreatorModel = SettingsField( default_factory=CreatorModel, title="Create VDB Cache") - CreateVrayROP: CreatorModel = Field( + CreateVrayROP: CreatorModel = SettingsField( default_factory=CreatorModel, title="Create VRay ROP") diff --git a/server_addon/houdini/server/settings/general.py b/server_addon/houdini/server/settings/general.py index aee44f1648..b71feae554 100644 --- a/server_addon/houdini/server/settings/general.py +++ b/server_addon/houdini/server/settings/general.py @@ -1,12 +1,11 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class HoudiniVarModel(BaseSettingsModel): _layout = "expanded" - var: str = Field("", title="Var") - value: str = Field("", title="Value") - is_directory: bool = Field(False, title="Treat as directory") + var: str = SettingsField("", title="Var") + value: str = SettingsField("", title="Value") + is_directory: bool = SettingsField(False, title="Treat as directory") class UpdateHoudiniVarcontextModel(BaseSettingsModel): @@ -16,20 +15,20 @@ class UpdateHoudiniVarcontextModel(BaseSettingsModel): it will be ensured the folder exists. """ - enabled: bool = Field(title="Enabled") + enabled: bool = SettingsField(title="Enabled") # TODO this was dynamic dictionary '{var: path}' - houdini_vars: list[HoudiniVarModel] = Field( + houdini_vars: list[HoudiniVarModel] = SettingsField( default_factory=list, title="Houdini Vars" ) class GeneralSettingsModel(BaseSettingsModel): - add_self_publish_button: bool = Field( + add_self_publish_button: bool = SettingsField( False, title="Add Self Publish Button" ) - update_houdini_var_context: UpdateHoudiniVarcontextModel = Field( + update_houdini_var_context: UpdateHoudiniVarcontextModel = SettingsField( default_factory=UpdateHoudiniVarcontextModel, title="Update Houdini Vars on context change" ) diff --git a/server_addon/houdini/server/settings/imageio.py b/server_addon/houdini/server/settings/imageio.py index 88aa40ecd6..f4850c5df7 100644 --- a/server_addon/houdini/server/settings/imageio.py +++ b/server_addon/houdini/server/settings/imageio.py @@ -1,29 +1,29 @@ -from pydantic import Field, validator -from ayon_server.settings import BaseSettingsModel +from pydantic import validator +from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.settings.validators import ensure_unique_names class ImageIOConfigModel(BaseSettingsModel): - override_global_config: bool = Field( + override_global_config: bool = SettingsField( False, title="Override global OCIO config" ) - filepath: list[str] = Field( + filepath: list[str] = SettingsField( default_factory=list, title="Config path" ) class ImageIOFileRuleModel(BaseSettingsModel): - name: str = Field("", title="Rule name") - pattern: str = Field("", title="Regex pattern") - colorspace: str = Field("", title="Colorspace name") - ext: str = Field("", title="File extension") + name: str = SettingsField("", title="Rule name") + pattern: str = SettingsField("", title="Regex pattern") + colorspace: str = SettingsField("", title="Colorspace name") + ext: str = SettingsField("", title="File extension") class ImageIOFileRulesModel(BaseSettingsModel): - activate_host_rules: bool = Field(False) - rules: list[ImageIOFileRuleModel] = Field( + activate_host_rules: bool = SettingsField(False) + rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, title="Rules" ) @@ -35,14 +35,14 @@ class ImageIOFileRulesModel(BaseSettingsModel): class HoudiniImageIOModel(BaseSettingsModel): - activate_host_color_management: bool = Field( + activate_host_color_management: bool = SettingsField( True, title="Enable Color Management" ) - ocio_config: ImageIOConfigModel = Field( + ocio_config: ImageIOConfigModel = SettingsField( default_factory=ImageIOConfigModel, title="OCIO config" ) - file_rules: ImageIOFileRulesModel = Field( + file_rules: ImageIOFileRulesModel = SettingsField( default_factory=ImageIOFileRulesModel, title="File Rules" ) diff --git a/server_addon/houdini/server/settings/main.py b/server_addon/houdini/server/settings/main.py index 9cfec54f22..cbb19d15b7 100644 --- a/server_addon/houdini/server/settings/main.py +++ b/server_addon/houdini/server/settings/main.py @@ -1,5 +1,4 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField from .general import ( GeneralSettingsModel, DEFAULT_GENERAL_SETTINGS @@ -17,23 +16,23 @@ from .publish import ( class HoudiniSettings(BaseSettingsModel): - general: GeneralSettingsModel = Field( + general: GeneralSettingsModel = SettingsField( default_factory=GeneralSettingsModel, title="General" ) - imageio: HoudiniImageIOModel = Field( + imageio: HoudiniImageIOModel = SettingsField( default_factory=HoudiniImageIOModel, title="Color Management (ImageIO)" ) - shelves: list[ShelvesModel] = Field( + shelves: list[ShelvesModel] = SettingsField( default_factory=list, title="Shelves Manager", ) - create: CreatePluginsModel = Field( + create: CreatePluginsModel = SettingsField( default_factory=CreatePluginsModel, title="Creator Plugins", ) - publish: PublishPluginsModel = Field( + publish: PublishPluginsModel = SettingsField( default_factory=PublishPluginsModel, title="Publish Plugins", ) diff --git a/server_addon/houdini/server/settings/publish.py b/server_addon/houdini/server/settings/publish.py index f551b3a209..1741568d63 100644 --- a/server_addon/houdini/server/settings/publish.py +++ b/server_addon/houdini/server/settings/publish.py @@ -1,5 +1,4 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField # Publish Plugins @@ -9,64 +8,64 @@ class CollectAssetHandlesModel(BaseSettingsModel): ignore start and end handles specified in the asset data for publish instances """ - use_asset_handles: bool = Field( + use_asset_handles: bool = SettingsField( title="Use asset handles") class CollectChunkSizeModel(BaseSettingsModel): """Collect Chunk Size.""" - enabled: bool = Field(title="Enabled") - optional: bool = Field(title="Optional") - chunk_size: int = Field( + enabled: bool = SettingsField(title="Enabled") + optional: bool = SettingsField(title="Optional") + chunk_size: int = SettingsField( title="Frames Per Task") class ValidateWorkfilePathsModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - optional: bool = Field(title="Optional") - node_types: list[str] = Field( + enabled: bool = SettingsField(title="Enabled") + optional: bool = SettingsField(title="Optional") + node_types: list[str] = SettingsField( default_factory=list, title="Node Types" ) - prohibited_vars: list[str] = Field( + prohibited_vars: list[str] = SettingsField( default_factory=list, title="Prohibited Variables" ) class BasicValidateModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") + enabled: bool = SettingsField(title="Enabled") + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") class PublishPluginsModel(BaseSettingsModel): - CollectAssetHandles: CollectAssetHandlesModel = Field( + CollectAssetHandles: CollectAssetHandlesModel = SettingsField( default_factory=CollectAssetHandlesModel, title="Collect Asset Handles.", section="Collectors" ) - CollectChunkSize: CollectChunkSizeModel = Field( + CollectChunkSize: CollectChunkSizeModel = SettingsField( default_factory=CollectChunkSizeModel, title="Collect Chunk Size." ) - ValidateContainers: BasicValidateModel = Field( + ValidateContainers: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Latest Containers.", section="Validators") - ValidateMeshIsStatic: BasicValidateModel = Field( + ValidateMeshIsStatic: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Mesh is Static.") - ValidateReviewColorspace: BasicValidateModel = Field( + ValidateReviewColorspace: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Review Colorspace.") - ValidateSubsetName: BasicValidateModel = Field( + ValidateSubsetName: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Subset Name.") - ValidateUnrealStaticMeshName: BasicValidateModel = Field( + ValidateUnrealStaticMeshName: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Unreal Static Mesh Name.") - ValidateWorkfilePaths: ValidateWorkfilePathsModel = Field( + ValidateWorkfilePaths: ValidateWorkfilePathsModel = SettingsField( default_factory=ValidateWorkfilePathsModel, title="Validate workfile paths settings.") diff --git a/server_addon/houdini/server/settings/shelves.py b/server_addon/houdini/server/settings/shelves.py index 133c18f77c..f6d7f1d06c 100644 --- a/server_addon/houdini/server/settings/shelves.py +++ b/server_addon/houdini/server/settings/shelves.py @@ -1,37 +1,37 @@ -from pydantic import Field from ayon_server.settings import ( BaseSettingsModel, + SettingsField, MultiplatformPathModel ) class ShelfToolsModel(BaseSettingsModel): """Name and Script Path are mandatory.""" - label: str = Field(title="Name") - script: str = Field(title="Script Path") - icon: str = Field("", title="Icon Path") - help: str = Field("", title="Help text") + label: str = SettingsField(title="Name") + script: str = SettingsField(title="Script Path") + icon: str = SettingsField("", title="Icon Path") + help: str = SettingsField("", title="Help text") class ShelfDefinitionModel(BaseSettingsModel): _layout = "expanded" - shelf_name: str = Field(title="Shelf name") - tools_list: list[ShelfToolsModel] = Field( + shelf_name: str = SettingsField(title="Shelf name") + tools_list: list[ShelfToolsModel] = SettingsField( default_factory=list, title="Shelf Tools" ) class AddShelfFileModel(BaseSettingsModel): - shelf_set_source_path: MultiplatformPathModel = Field( + shelf_set_source_path: MultiplatformPathModel = SettingsField( default_factory=MultiplatformPathModel, title="Shelf Set Path" ) class AddSetAndDefinitionsModel(BaseSettingsModel): - shelf_set_name: str = Field("", title="Shelf Set Name") - shelf_definition: list[ShelfDefinitionModel] = Field( + shelf_set_name: str = SettingsField("", title="Shelf Set Name") + shelf_definition: list[ShelfDefinitionModel] = SettingsField( default_factory=list, title="Shelves Definitions" ) @@ -51,17 +51,17 @@ def shelves_enum_options(): class ShelvesModel(BaseSettingsModel): - options: str = Field( + options: str = SettingsField( title="Options", description="Switch between shelves manager options", enum_resolver=shelves_enum_options, conditionalEnum=True ) - add_shelf_file: AddShelfFileModel = Field( + add_shelf_file: AddShelfFileModel = SettingsField( title="Add a .shelf file", default_factory=AddShelfFileModel ) - add_set_and_definitions: AddSetAndDefinitionsModel = Field( + add_set_and_definitions: AddSetAndDefinitionsModel = SettingsField( title="Add Shelf Set Name and Shelves Definitions", default_factory=AddSetAndDefinitionsModel ) diff --git a/server_addon/kitsu/server/__init__.py b/server_addon/kitsu/server/__init__.py deleted file mode 100644 index 69cf812dea..0000000000 --- a/server_addon/kitsu/server/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Type - -from ayon_server.addons import BaseServerAddon - -from .version import __version__ -from .settings import KitsuSettings, DEFAULT_VALUES - - -class KitsuAddon(BaseServerAddon): - name = "kitsu" - title = "Kitsu" - version = __version__ - settings_model: Type[KitsuSettings] = KitsuSettings - frontend_scopes = {} - services = {} - - async def get_default_settings(self): - settings_model_cls = self.get_settings_model() - return settings_model_cls(**DEFAULT_VALUES) diff --git a/server_addon/kitsu/server/settings.py b/server_addon/kitsu/server/settings.py deleted file mode 100644 index a4d10d889d..0000000000 --- a/server_addon/kitsu/server/settings.py +++ /dev/null @@ -1,112 +0,0 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel - - -class EntityPattern(BaseSettingsModel): - episode: str = Field(title="Episode") - sequence: str = Field(title="Sequence") - shot: str = Field(title="Shot") - - -def _status_change_cond_enum(): - return [ - {"value": "equal", "label": "Equal"}, - {"value": "not_equal", "label": "Not equal"} - ] - - -class StatusChangeCondition(BaseSettingsModel): - condition: str = Field( - "equal", - enum_resolver=_status_change_cond_enum, - title="Condition" - ) - short_name: str = Field("", title="Short name") - - -class StatusChangeProductTypeRequirementModel(BaseSettingsModel): - condition: str = Field( - "equal", - enum_resolver=_status_change_cond_enum, - title="Condition" - ) - product_type: str = Field("", title="Product type") - - -class StatusChangeConditionsModel(BaseSettingsModel): - status_conditions: list[StatusChangeCondition] = Field( - default_factory=list, - title="Status conditions" - ) - product_type_requirements: list[StatusChangeProductTypeRequirementModel] = Field( - default_factory=list, - title="Product type requirements") - - -class CustomCommentTemplateModel(BaseSettingsModel): - enabled: bool = Field(True) - comment_template: str = Field("", title="Custom comment") - - -class IntegrateKitsuNotes(BaseSettingsModel): - """Kitsu supports markdown and here you can create a custom comment template. - - You can use data from your publishing instance's data. - """ - - set_status_note: bool = Field(title="Set status on note") - note_status_shortname: str = Field(title="Note shortname") - status_change_conditions: StatusChangeConditionsModel = Field( - default_factory=StatusChangeConditionsModel, - title="Status change conditions" - ) - custom_comment_template: CustomCommentTemplateModel = Field( - default_factory=CustomCommentTemplateModel, - title="Custom Comment Template", - ) - - -class PublishPlugins(BaseSettingsModel): - IntegrateKitsuNote: IntegrateKitsuNotes = Field( - default_factory=IntegrateKitsuNotes, - title="Integrate Kitsu Note" - ) - - -class KitsuSettings(BaseSettingsModel): - server: str = Field( - "", - title="Kitsu Server", - scope=["studio"], - ) - entities_naming_pattern: EntityPattern = Field( - default_factory=EntityPattern, - title="Entities naming pattern", - ) - publish: PublishPlugins = Field( - default_factory=PublishPlugins, - title="Publish plugins", - ) - - -DEFAULT_VALUES = { - "entities_naming_pattern": { - "episode": "E##", - "sequence": "SQ##", - "shot": "SH##" - }, - "publish": { - "IntegrateKitsuNote": { - "set_status_note": False, - "note_status_shortname": "wfa", - "status_change_conditions": { - "status_conditions": [], - "product_type_requirements": [] - }, - "custom_comment_template": { - "enabled": False, - "comment_template": "{comment}\n\n| | |\n|--|--|\n| version| `{version}` |\n| product type | `{product[type]}` |\n| name | `{name}` |" - } - } - } -} diff --git a/server_addon/kitsu/server/version.py b/server_addon/kitsu/server/version.py deleted file mode 100644 index 485f44ac21..0000000000 --- a/server_addon/kitsu/server/version.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "0.1.1" diff --git a/server_addon/max/server/settings/create_review_settings.py b/server_addon/max/server/settings/create_review_settings.py index 43dac0730a..807976a391 100644 --- a/server_addon/max/server/settings/create_review_settings.py +++ b/server_addon/max/server/settings/create_review_settings.py @@ -1,6 +1,4 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField def image_format_enum(): @@ -57,27 +55,27 @@ def anti_aliasing_enum(): class CreateReviewModel(BaseSettingsModel): - review_width: int = Field(1920, title="Review Width") - review_height: int = Field(1080, title="Review Height") - percentSize: float = Field(100.0, title="Percent of Output") - keep_images: bool = Field(False, title="Keep Image Sequences") - image_format: str = Field( + review_width: int = SettingsField(1920, title="Review Width") + review_height: int = SettingsField(1080, title="Review Height") + percentSize: float = SettingsField(100.0, title="Percent of Output") + keep_images: bool = SettingsField(False, title="Keep Image Sequences") + image_format: str = SettingsField( enum_resolver=image_format_enum, title="Image Format Options" ) - visual_style: str = Field( + visual_style: str = SettingsField( enum_resolver=visual_style_enum, title="Preference" ) - viewport_preset: str = Field( + viewport_preset: str = SettingsField( enum_resolver=preview_preset_enum, title="Preview Preset" ) - anti_aliasing: str = Field( + anti_aliasing: str = SettingsField( enum_resolver=anti_aliasing_enum, title="Anti-aliasing Quality" ) - vp_texture: bool = Field(True, title="Viewport Texture") + vp_texture: bool = SettingsField(True, title="Viewport Texture") DEFAULT_CREATE_REVIEW_SETTINGS = { diff --git a/server_addon/max/server/settings/imageio.py b/server_addon/max/server/settings/imageio.py index 5e46104fa7..221f85a41f 100644 --- a/server_addon/max/server/settings/imageio.py +++ b/server_addon/max/server/settings/imageio.py @@ -1,29 +1,29 @@ -from pydantic import Field, validator -from ayon_server.settings import BaseSettingsModel +from pydantic import validator +from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.settings.validators import ensure_unique_names class ImageIOConfigModel(BaseSettingsModel): - override_global_config: bool = Field( + override_global_config: bool = SettingsField( False, title="Override global OCIO config" ) - filepath: list[str] = Field( + filepath: list[str] = SettingsField( default_factory=list, title="Config path" ) class ImageIOFileRuleModel(BaseSettingsModel): - name: str = Field("", title="Rule name") - pattern: str = Field("", title="Regex pattern") - colorspace: str = Field("", title="Colorspace name") - ext: str = Field("", title="File extension") + name: str = SettingsField("", title="Rule name") + pattern: str = SettingsField("", title="Regex pattern") + colorspace: str = SettingsField("", title="Colorspace name") + ext: str = SettingsField("", title="File extension") class ImageIOFileRulesModel(BaseSettingsModel): - activate_host_rules: bool = Field(False) - rules: list[ImageIOFileRuleModel] = Field( + activate_host_rules: bool = SettingsField(False) + rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, title="Rules" ) @@ -35,14 +35,14 @@ class ImageIOFileRulesModel(BaseSettingsModel): class ImageIOSettings(BaseSettingsModel): - activate_host_color_management: bool = Field( + activate_host_color_management: bool = SettingsField( True, title="Enable Color Management" ) - ocio_config: ImageIOConfigModel = Field( + ocio_config: ImageIOConfigModel = SettingsField( default_factory=ImageIOConfigModel, title="OCIO config" ) - file_rules: ImageIOFileRulesModel = Field( + file_rules: ImageIOFileRulesModel = SettingsField( default_factory=ImageIOFileRulesModel, title="File Rules" ) diff --git a/server_addon/max/server/settings/main.py b/server_addon/max/server/settings/main.py index cad6024cf7..7b0bfc6421 100644 --- a/server_addon/max/server/settings/main.py +++ b/server_addon/max/server/settings/main.py @@ -1,5 +1,4 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField from .imageio import ImageIOSettings from .render_settings import ( RenderSettingsModel, DEFAULT_RENDER_SETTINGS @@ -23,8 +22,8 @@ def unit_scale_enum(): class UnitScaleSettings(BaseSettingsModel): - enabled: bool = Field(True, title="Enabled") - scene_unit_scale: str = Field( + enabled: bool = SettingsField(True, title="Enabled") + scene_unit_scale: str = SettingsField( "Centimeters", title="Scene Unit Scale", enum_resolver=unit_scale_enum @@ -33,37 +32,37 @@ class UnitScaleSettings(BaseSettingsModel): class PRTAttributesModel(BaseSettingsModel): _layout = "compact" - name: str = Field(title="Name") - value: str = Field(title="Attribute") + name: str = SettingsField(title="Name") + value: str = SettingsField(title="Attribute") class PointCloudSettings(BaseSettingsModel): - attribute: list[PRTAttributesModel] = Field( + attribute: list[PRTAttributesModel] = SettingsField( default_factory=list, title="Channel Attribute") class MaxSettings(BaseSettingsModel): - unit_scale_settings: UnitScaleSettings = Field( + unit_scale_settings: UnitScaleSettings = SettingsField( default_factory=UnitScaleSettings, title="Set Unit Scale" ) - imageio: ImageIOSettings = Field( + imageio: ImageIOSettings = SettingsField( default_factory=ImageIOSettings, title="Color Management (ImageIO)" ) - RenderSettings: RenderSettingsModel = Field( + RenderSettings: RenderSettingsModel = SettingsField( default_factory=RenderSettingsModel, title="Render Settings" ) - CreateReview: CreateReviewModel = Field( + CreateReview: CreateReviewModel = SettingsField( default_factory=CreateReviewModel, title="Create Review" ) - PointCloud: PointCloudSettings = Field( + PointCloud: PointCloudSettings = SettingsField( default_factory=PointCloudSettings, title="Point Cloud" ) - publish: PublishersModel = Field( + publish: PublishersModel = SettingsField( default_factory=PublishersModel, title="Publish Plugins") diff --git a/server_addon/max/server/settings/publishers.py b/server_addon/max/server/settings/publishers.py index d40d85a99b..da782cb494 100644 --- a/server_addon/max/server/settings/publishers.py +++ b/server_addon/max/server/settings/publishers.py @@ -1,13 +1,13 @@ import json -from pydantic import Field, validator +from pydantic import validator -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.exceptions import BadRequestException class ValidateAttributesModel(BaseSettingsModel): - enabled: bool = Field(title="ValidateAttributes") - attributes: str = Field( + enabled: bool = SettingsField(title="ValidateAttributes") + attributes: str = SettingsField( "{}", title="Attributes", widget="textarea") @validator("attributes") @@ -28,64 +28,64 @@ class ValidateAttributesModel(BaseSettingsModel): class FamilyMappingItemModel(BaseSettingsModel): - product_types: list[str] = Field( + product_types: list[str] = SettingsField( default_factory=list, title="Product Types" ) - plugins: list[str] = Field( + plugins: list[str] = SettingsField( default_factory=list, title="Plugins" ) class ValidateLoadedPluginModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - optional: bool = Field(title="Optional") - family_plugins_mapping: list[FamilyMappingItemModel] = Field( + enabled: bool = SettingsField(title="Enabled") + optional: bool = SettingsField(title="Optional") + family_plugins_mapping: list[FamilyMappingItemModel] = SettingsField( default_factory=list, title="Family Plugins Mapping" ) class BasicValidateModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") + enabled: bool = SettingsField(title="Enabled") + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") class PublishersModel(BaseSettingsModel): - ValidateFrameRange: BasicValidateModel = Field( + ValidateFrameRange: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Frame Range", section="Validators" ) - ValidateAttributes: ValidateAttributesModel = Field( + ValidateAttributes: ValidateAttributesModel = SettingsField( default_factory=ValidateAttributesModel, title="Validate Attributes" ) - ValidateLoadedPlugin: ValidateLoadedPluginModel = Field( + ValidateLoadedPlugin: ValidateLoadedPluginModel = SettingsField( default_factory=ValidateLoadedPluginModel, title="Validate Loaded Plugin" ) - ExtractModelObj: BasicValidateModel = Field( + ExtractModelObj: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Extract OBJ", section="Extractors" ) - ExtractModelFbx: BasicValidateModel = Field( + ExtractModelFbx: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Extract FBX" ) - ExtractModelUSD: BasicValidateModel = Field( + ExtractModelUSD: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Extract Geometry (USD)" ) - ExtractModel: BasicValidateModel = Field( + ExtractModel: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Extract Geometry (Alembic)" ) - ExtractMaxSceneRaw: BasicValidateModel = Field( + ExtractMaxSceneRaw: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Extract Max Scene (Raw)" ) diff --git a/server_addon/max/server/settings/render_settings.py b/server_addon/max/server/settings/render_settings.py index c00cb5e436..19d36dd0f8 100644 --- a/server_addon/max/server/settings/render_settings.py +++ b/server_addon/max/server/settings/render_settings.py @@ -1,6 +1,4 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField def aov_separators_enum(): @@ -26,19 +24,19 @@ def image_format_enum(): class RenderSettingsModel(BaseSettingsModel): - default_render_image_folder: str = Field( + default_render_image_folder: str = SettingsField( title="Default render image folder" ) - aov_separator: str = Field( + aov_separator: str = SettingsField( "underscore", title="AOV Separator character", enum_resolver=aov_separators_enum ) - image_format: str = Field( + image_format: str = SettingsField( enum_resolver=image_format_enum, title="Output Image Format" ) - multipass: bool = Field(title="multipass") + multipass: bool = SettingsField(title="multipass") DEFAULT_RENDER_SETTINGS = { diff --git a/server_addon/maya/server/settings/creators.py b/server_addon/maya/server/settings/creators.py index 34a54832af..5f3b850a1f 100644 --- a/server_addon/maya/server/settings/creators.py +++ b/server_addon/maya/server/settings/creators.py @@ -1,232 +1,235 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel -from ayon_server.settings import task_types_enum +from ayon_server.settings import ( + BaseSettingsModel, + SettingsField, + task_types_enum, +) class CreateLookModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - make_tx: bool = Field(title="Make tx files") - rs_tex: bool = Field(title="Make Redshift texture files") - default_variants: list[str] = Field( + enabled: bool = SettingsField(title="Enabled") + make_tx: bool = SettingsField(title="Make tx files") + rs_tex: bool = SettingsField(title="Make Redshift texture files") + default_variants: list[str] = SettingsField( default_factory=list, title="Default Products" ) class BasicCreatorModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - default_variants: list[str] = Field( + enabled: bool = SettingsField(title="Enabled") + default_variants: list[str] = SettingsField( default_factory=list, title="Default Products" ) class CreateUnrealStaticMeshModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - default_variants: list[str] = Field( + enabled: bool = SettingsField(title="Enabled") + default_variants: list[str] = SettingsField( default_factory=list, title="Default Products" ) - static_mesh_prefix: str = Field("S", title="Static Mesh Prefix") - collision_prefixes: list[str] = Field( + static_mesh_prefix: str = SettingsField("S", title="Static Mesh Prefix") + collision_prefixes: list[str] = SettingsField( default_factory=list, title="Collision Prefixes" ) class CreateUnrealSkeletalMeshModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - default_variants: list[str] = Field( + enabled: bool = SettingsField(title="Enabled") + default_variants: list[str] = SettingsField( default_factory=list, title="Default Products") - joint_hints: str = Field("jnt_org", title="Joint root hint") + joint_hints: str = SettingsField("jnt_org", title="Joint root hint") class CreateMultiverseLookModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - publish_mip_map: bool = Field(title="publish_mip_map") + enabled: bool = SettingsField(title="Enabled") + publish_mip_map: bool = SettingsField(title="publish_mip_map") class BasicExportMeshModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - write_color_sets: bool = Field(title="Write Color Sets") - write_face_sets: bool = Field(title="Write Face Sets") - default_variants: list[str] = Field( + enabled: bool = SettingsField(title="Enabled") + write_color_sets: bool = SettingsField(title="Write Color Sets") + write_face_sets: bool = SettingsField(title="Write Face Sets") + default_variants: list[str] = SettingsField( default_factory=list, title="Default Products" ) class CreateAnimationModel(BaseSettingsModel): - write_color_sets: bool = Field(title="Write Color Sets") - write_face_sets: bool = Field(title="Write Face Sets") - include_parent_hierarchy: bool = Field( + write_color_sets: bool = SettingsField(title="Write Color Sets") + write_face_sets: bool = SettingsField(title="Write Face Sets") + include_parent_hierarchy: bool = SettingsField( title="Include Parent Hierarchy") - include_user_defined_attributes: bool = Field( + include_user_defined_attributes: bool = SettingsField( title="Include User Defined Attributes") - default_variants: list[str] = Field( + default_variants: list[str] = SettingsField( default_factory=list, title="Default Products" ) class CreatePointCacheModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - write_color_sets: bool = Field(title="Write Color Sets") - write_face_sets: bool = Field(title="Write Face Sets") - include_user_defined_attributes: bool = Field( + enabled: bool = SettingsField(title="Enabled") + write_color_sets: bool = SettingsField(title="Write Color Sets") + write_face_sets: bool = SettingsField(title="Write Face Sets") + include_user_defined_attributes: bool = SettingsField( title="Include User Defined Attributes" ) - default_variants: list[str] = Field( + default_variants: list[str] = SettingsField( default_factory=list, title="Default Products" ) class CreateProxyAlembicModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - write_color_sets: bool = Field(title="Write Color Sets") - write_face_sets: bool = Field(title="Write Face Sets") - default_variants: list[str] = Field( + enabled: bool = SettingsField(title="Enabled") + write_color_sets: bool = SettingsField(title="Write Color Sets") + write_face_sets: bool = SettingsField(title="Write Face Sets") + default_variants: list[str] = SettingsField( default_factory=list, title="Default Products" ) class CreateAssModel(BasicCreatorModel): - expandProcedurals: bool = Field(title="Expand Procedurals") - motionBlur: bool = Field(title="Motion Blur") - motionBlurKeys: int = Field(2, title="Motion Blur Keys") - motionBlurLength: float = Field(0.5, title="Motion Blur Length") - maskOptions: bool = Field(title="Mask Options") - maskCamera: bool = Field(title="Mask Camera") - maskLight: bool = Field(title="Mask Light") - maskShape: bool = Field(title="Mask Shape") - maskShader: bool = Field(title="Mask Shader") - maskOverride: bool = Field(title="Mask Override") - maskDriver: bool = Field(title="Mask Driver") - maskFilter: bool = Field(title="Mask Filter") - maskColor_manager: bool = Field(title="Mask Color Manager") - maskOperator: bool = Field(title="Mask Operator") + expandProcedurals: bool = SettingsField(title="Expand Procedurals") + motionBlur: bool = SettingsField(title="Motion Blur") + motionBlurKeys: int = SettingsField(2, title="Motion Blur Keys") + motionBlurLength: float = SettingsField(0.5, title="Motion Blur Length") + maskOptions: bool = SettingsField(title="Mask Options") + maskCamera: bool = SettingsField(title="Mask Camera") + maskLight: bool = SettingsField(title="Mask Light") + maskShape: bool = SettingsField(title="Mask Shape") + maskShader: bool = SettingsField(title="Mask Shader") + maskOverride: bool = SettingsField(title="Mask Override") + maskDriver: bool = SettingsField(title="Mask Driver") + maskFilter: bool = SettingsField(title="Mask Filter") + maskColor_manager: bool = SettingsField(title="Mask Color Manager") + maskOperator: bool = SettingsField(title="Mask Operator") class CreateReviewModel(BasicCreatorModel): - useMayaTimeline: bool = Field(title="Use Maya Timeline for Frame Range.") + useMayaTimeline: bool = SettingsField( + title="Use Maya Timeline for Frame Range." + ) class CreateVrayProxyModel(BaseSettingsModel): - enabled: bool = Field(True) - vrmesh: bool = Field(title="VrMesh") - alembic: bool = Field(title="Alembic") - default_variants: list[str] = Field( + enabled: bool = SettingsField(True) + vrmesh: bool = SettingsField(title="VrMesh") + alembic: bool = SettingsField(title="Alembic") + default_variants: list[str] = SettingsField( default_factory=list, title="Default Products") class CreateMultishotLayout(BasicCreatorModel): - shotParent: str = Field(title="Shot Parent Folder") - groupLoadedAssets: bool = Field(title="Group Loaded Assets") - task_type: list[str] = Field( + shotParent: str = SettingsField(title="Shot Parent Folder") + groupLoadedAssets: bool = SettingsField(title="Group Loaded Assets") + task_type: list[str] = SettingsField( title="Task types", enum_resolver=task_types_enum ) - task_name: str = Field(title="Task name (regex)") + task_name: str = SettingsField(title="Task name (regex)") class CreatorsModel(BaseSettingsModel): - CreateLook: CreateLookModel = Field( + CreateLook: CreateLookModel = SettingsField( default_factory=CreateLookModel, title="Create Look" ) - CreateRender: BasicCreatorModel = Field( + CreateRender: BasicCreatorModel = SettingsField( default_factory=BasicCreatorModel, title="Create Render" ) # "-" is not compatible in the new model - CreateUnrealStaticMesh: CreateUnrealStaticMeshModel = Field( + CreateUnrealStaticMesh: CreateUnrealStaticMeshModel = SettingsField( default_factory=CreateUnrealStaticMeshModel, title="Create Unreal_Static Mesh" ) # "-" is not compatible in the new model - CreateUnrealSkeletalMesh: CreateUnrealSkeletalMeshModel = Field( + CreateUnrealSkeletalMesh: CreateUnrealSkeletalMeshModel = SettingsField( default_factory=CreateUnrealSkeletalMeshModel, title="Create Unreal_Skeletal Mesh" ) - CreateMultiverseLook: CreateMultiverseLookModel = Field( + CreateMultiverseLook: CreateMultiverseLookModel = SettingsField( default_factory=CreateMultiverseLookModel, title="Create Multiverse Look" ) - CreateAnimation: CreateAnimationModel = Field( + CreateAnimation: CreateAnimationModel = SettingsField( default_factory=CreateAnimationModel, title="Create Animation" ) - CreateModel: BasicExportMeshModel = Field( + CreateModel: BasicExportMeshModel = SettingsField( default_factory=BasicExportMeshModel, title="Create Model" ) - CreatePointCache: CreatePointCacheModel = Field( + CreatePointCache: CreatePointCacheModel = SettingsField( default_factory=CreatePointCacheModel, title="Create Point Cache" ) - CreateProxyAlembic: CreateProxyAlembicModel = Field( + CreateProxyAlembic: CreateProxyAlembicModel = SettingsField( default_factory=CreateProxyAlembicModel, title="Create Proxy Alembic" ) - CreateMultiverseUsd: BasicCreatorModel = Field( + CreateMultiverseUsd: BasicCreatorModel = SettingsField( default_factory=BasicCreatorModel, title="Create Multiverse USD" ) - CreateMultiverseUsdComp: BasicCreatorModel = Field( + CreateMultiverseUsdComp: BasicCreatorModel = SettingsField( default_factory=BasicCreatorModel, title="Create Multiverse USD Composition" ) - CreateMultiverseUsdOver: BasicCreatorModel = Field( + CreateMultiverseUsdOver: BasicCreatorModel = SettingsField( default_factory=BasicCreatorModel, title="Create Multiverse USD Override" ) - CreateAss: CreateAssModel = Field( + CreateAss: CreateAssModel = SettingsField( default_factory=CreateAssModel, title="Create Ass" ) - CreateAssembly: BasicCreatorModel = Field( + CreateAssembly: BasicCreatorModel = SettingsField( default_factory=BasicCreatorModel, title="Create Assembly" ) - CreateCamera: BasicCreatorModel = Field( + CreateCamera: BasicCreatorModel = SettingsField( default_factory=BasicCreatorModel, title="Create Camera" ) - CreateLayout: BasicCreatorModel = Field( + CreateLayout: BasicCreatorModel = SettingsField( default_factory=BasicCreatorModel, title="Create Layout" ) - CreateMayaScene: BasicCreatorModel = Field( + CreateMayaScene: BasicCreatorModel = SettingsField( default_factory=BasicCreatorModel, title="Create Maya Scene" ) - CreateRenderSetup: BasicCreatorModel = Field( + CreateRenderSetup: BasicCreatorModel = SettingsField( default_factory=BasicCreatorModel, title="Create Render Setup" ) - CreateReview: CreateReviewModel = Field( + CreateReview: CreateReviewModel = SettingsField( default_factory=CreateReviewModel, title="Create Review" ) - CreateRig: BasicCreatorModel = Field( + CreateRig: BasicCreatorModel = SettingsField( default_factory=BasicCreatorModel, title="Create Rig" ) - CreateSetDress: BasicCreatorModel = Field( + CreateSetDress: BasicCreatorModel = SettingsField( default_factory=BasicCreatorModel, title="Create Set Dress" ) - CreateVrayProxy: CreateVrayProxyModel = Field( + CreateVrayProxy: CreateVrayProxyModel = SettingsField( default_factory=CreateVrayProxyModel, title="Create VRay Proxy" ) - CreateVRayScene: BasicCreatorModel = Field( + CreateVRayScene: BasicCreatorModel = SettingsField( default_factory=BasicCreatorModel, title="Create VRay Scene" ) - CreateYetiRig: BasicCreatorModel = Field( + CreateYetiRig: BasicCreatorModel = SettingsField( default_factory=BasicCreatorModel, title="Create Yeti Rig" ) diff --git a/server_addon/maya/server/settings/explicit_plugins_loading.py b/server_addon/maya/server/settings/explicit_plugins_loading.py index 394adb728f..cda5154b90 100644 --- a/server_addon/maya/server/settings/explicit_plugins_loading.py +++ b/server_addon/maya/server/settings/explicit_plugins_loading.py @@ -1,19 +1,17 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class PluginsModel(BaseSettingsModel): _layout = "expanded" - enabled: bool = Field(title="Enabled") - name: str = Field("", title="Name") + enabled: bool = SettingsField(title="Enabled") + name: str = SettingsField("", title="Name") class ExplicitPluginsLoadingModel(BaseSettingsModel): """Maya Explicit Plugins Loading.""" _isGroup: bool = True - enabled: bool = Field(title="enabled") - plugins_to_load: list[PluginsModel] = Field( + enabled: bool = SettingsField(title="enabled") + plugins_to_load: list[PluginsModel] = SettingsField( default_factory=list, title="Plugins To Load" ) diff --git a/server_addon/maya/server/settings/imageio.py b/server_addon/maya/server/settings/imageio.py index 946a14c866..f4cdf3fbff 100644 --- a/server_addon/maya/server/settings/imageio.py +++ b/server_addon/maya/server/settings/imageio.py @@ -2,32 +2,36 @@ Note: Names were changed to get rid of the versions in class names. """ -from pydantic import Field, validator +from pydantic import validator -from ayon_server.settings import BaseSettingsModel, ensure_unique_names +from ayon_server.settings import ( + BaseSettingsModel, + SettingsField, + ensure_unique_names, +) class ImageIOConfigModel(BaseSettingsModel): - override_global_config: bool = Field( + override_global_config: bool = SettingsField( False, title="Override global OCIO config" ) - filepath: list[str] = Field( + filepath: list[str] = SettingsField( default_factory=list, title="Config path" ) class ImageIOFileRuleModel(BaseSettingsModel): - name: str = Field("", title="Rule name") - pattern: str = Field("", title="Regex pattern") - colorspace: str = Field("", title="Colorspace name") - ext: str = Field("", title="File extension") + name: str = SettingsField("", title="Rule name") + pattern: str = SettingsField("", title="Regex pattern") + colorspace: str = SettingsField("", title="Colorspace name") + ext: str = SettingsField("", title="File extension") class ImageIOFileRulesModel(BaseSettingsModel): - activate_host_rules: bool = Field(False) - rules: list[ImageIOFileRuleModel] = Field( + activate_host_rules: bool = SettingsField(False) + rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, title="Rules" ) @@ -44,25 +48,27 @@ class ColorManagementPreferenceV2Model(BaseSettingsModel): Please migrate all to 'imageio/workfile' and enable it. """ - enabled: bool = Field(True, title="Use Color Management Preference v2") + enabled: bool = SettingsField( + True, title="Use Color Management Preference v2" + ) - renderSpace: str = Field(title="Rendering Space") - displayName: str = Field(title="Display") - viewName: str = Field(title="View") + renderSpace: str = SettingsField(title="Rendering Space") + displayName: str = SettingsField(title="Display") + viewName: str = SettingsField(title="View") class ColorManagementPreferenceModel(BaseSettingsModel): """Color Management Preference (legacy).""" - renderSpace: str = Field(title="Rendering Space") - viewTransform: str = Field(title="Viewer Transform ") + renderSpace: str = SettingsField(title="Rendering Space") + viewTransform: str = SettingsField(title="Viewer Transform ") class WorkfileImageIOModel(BaseSettingsModel): - enabled: bool = Field(True, title="Enabled") - renderSpace: str = Field(title="Rendering Space") - displayName: str = Field(title="Display") - viewName: str = Field(title="View") + enabled: bool = SettingsField(True, title="Enabled") + renderSpace: str = SettingsField(title="Rendering Space") + displayName: str = SettingsField(title="Display") + viewName: str = SettingsField(title="View") class ImageIOSettings(BaseSettingsModel): @@ -72,27 +78,29 @@ class ImageIOSettings(BaseSettingsModel): """ _isGroup: bool = True - activate_host_color_management: bool = Field( + activate_host_color_management: bool = SettingsField( True, title="Enable Color Management" ) - ocio_config: ImageIOConfigModel = Field( + ocio_config: ImageIOConfigModel = SettingsField( default_factory=ImageIOConfigModel, title="OCIO config" ) - file_rules: ImageIOFileRulesModel = Field( + file_rules: ImageIOFileRulesModel = SettingsField( default_factory=ImageIOFileRulesModel, title="File Rules" ) - workfile: WorkfileImageIOModel = Field( + workfile: WorkfileImageIOModel = SettingsField( default_factory=WorkfileImageIOModel, title="Workfile" ) # Deprecated - colorManagementPreference_v2: ColorManagementPreferenceV2Model = Field( - default_factory=ColorManagementPreferenceV2Model, - title="DEPRECATED: Color Management Preference v2 (Maya 2022+)" + colorManagementPreference_v2: ColorManagementPreferenceV2Model = ( + SettingsField( + default_factory=ColorManagementPreferenceV2Model, + title="DEPRECATED: Color Management Preference v2 (Maya 2022+)" + ) ) - colorManagementPreference: ColorManagementPreferenceModel = Field( + colorManagementPreference: ColorManagementPreferenceModel = SettingsField( default_factory=ColorManagementPreferenceModel, title="DEPRECATED: Color Management Preference (legacy)" ) diff --git a/server_addon/maya/server/settings/include_handles.py b/server_addon/maya/server/settings/include_handles.py index 3ba6aca66b..931222ad2d 100644 --- a/server_addon/maya/server/settings/include_handles.py +++ b/server_addon/maya/server/settings/include_handles.py @@ -1,24 +1,26 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel, task_types_enum +from ayon_server.settings import ( + BaseSettingsModel, + SettingsField, + task_types_enum, +) class IncludeByTaskTypeModel(BaseSettingsModel): - task_type: list[str] = Field( + task_type: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - include_handles: bool = Field(True, title="Include handles") + include_handles: bool = SettingsField(True, title="Include handles") class IncludeHandlesModel(BaseSettingsModel): """Maya dirmap settings.""" # _layout = "expanded" - include_handles_default: bool = Field( + include_handles_default: bool = SettingsField( True, title="Include handles by default" ) - per_task_type: list[IncludeByTaskTypeModel] = Field( + per_task_type: list[IncludeByTaskTypeModel] = SettingsField( default_factory=list, title="Include/exclude handles by task type" ) diff --git a/server_addon/maya/server/settings/loaders.py b/server_addon/maya/server/settings/loaders.py index ed6b6fd2ac..15d4275b80 100644 --- a/server_addon/maya/server/settings/loaders.py +++ b/server_addon/maya/server/settings/loaders.py @@ -1,66 +1,66 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.types import ColorRGBA_uint8 class ColorsSetting(BaseSettingsModel): - model: ColorRGBA_uint8 = Field( + model: ColorRGBA_uint8 = SettingsField( (209, 132, 30, 1.0), title="Model:") - rig: ColorRGBA_uint8 = Field( + rig: ColorRGBA_uint8 = SettingsField( (59, 226, 235, 1.0), title="Rig:") - pointcache: ColorRGBA_uint8 = Field( + pointcache: ColorRGBA_uint8 = SettingsField( (94, 209, 30, 1.0), title="Pointcache:") - animation: ColorRGBA_uint8 = Field( + animation: ColorRGBA_uint8 = SettingsField( (94, 209, 30, 1.0), title="Animation:") - ass: ColorRGBA_uint8 = Field( + ass: ColorRGBA_uint8 = SettingsField( (249, 135, 53, 1.0), title="Arnold StandIn:") - camera: ColorRGBA_uint8 = Field( + camera: ColorRGBA_uint8 = SettingsField( (136, 114, 244, 1.0), title="Camera:") - fbx: ColorRGBA_uint8 = Field( + fbx: ColorRGBA_uint8 = SettingsField( (215, 166, 255, 1.0), title="FBX:") - mayaAscii: ColorRGBA_uint8 = Field( + mayaAscii: ColorRGBA_uint8 = SettingsField( (67, 174, 255, 1.0), title="Maya Ascii:") - mayaScene: ColorRGBA_uint8 = Field( + mayaScene: ColorRGBA_uint8 = SettingsField( (67, 174, 255, 1.0), title="Maya Scene:") - setdress: ColorRGBA_uint8 = Field( + setdress: ColorRGBA_uint8 = SettingsField( (255, 250, 90, 1.0), title="Set Dress:") - layout: ColorRGBA_uint8 = Field(( + layout: ColorRGBA_uint8 = SettingsField(( 255, 250, 90, 1.0), title="Layout:") - vdbcache: ColorRGBA_uint8 = Field( + vdbcache: ColorRGBA_uint8 = SettingsField( (249, 54, 0, 1.0), title="VDB Cache:") - vrayproxy: ColorRGBA_uint8 = Field( + vrayproxy: ColorRGBA_uint8 = SettingsField( (255, 150, 12, 1.0), title="VRay Proxy:") - vrayscene_layer: ColorRGBA_uint8 = Field( + vrayscene_layer: ColorRGBA_uint8 = SettingsField( (255, 150, 12, 1.0), title="VRay Scene:") - yeticache: ColorRGBA_uint8 = Field( + yeticache: ColorRGBA_uint8 = SettingsField( (99, 206, 220, 1.0), title="Yeti Cache:") - yetiRig: ColorRGBA_uint8 = Field( + yetiRig: ColorRGBA_uint8 = SettingsField( (0, 205, 125, 1.0), title="Yeti Rig:") class ReferenceLoaderModel(BaseSettingsModel): - namespace: str = Field(title="Namespace") - group_name: str = Field(title="Group name") - display_handle: bool = Field(title="Display Handle On Load References") + namespace: str = SettingsField(title="Namespace") + group_name: str = SettingsField(title="Group name") + display_handle: bool = SettingsField( + title="Display Handle On Load References" + ) class ImportLoaderModel(BaseSettingsModel): - namespace: str = Field(title="Namespace") - group_name: str = Field(title="Group name") + namespace: str = SettingsField(title="Namespace") + group_name: str = SettingsField(title="Group name") class LoadersModel(BaseSettingsModel): - colors: ColorsSetting = Field( + colors: ColorsSetting = SettingsField( default_factory=ColorsSetting, title="Loaded Products Outliner Colors") - reference_loader: ReferenceLoaderModel = Field( + reference_loader: ReferenceLoaderModel = SettingsField( default_factory=ReferenceLoaderModel, title="Reference Loader" ) - import_loader: ImportLoaderModel = Field( + import_loader: ImportLoaderModel = SettingsField( default_factory=ImportLoaderModel, title="Import Loader" ) diff --git a/server_addon/maya/server/settings/main.py b/server_addon/maya/server/settings/main.py index 3d084312e9..f7f62e219d 100644 --- a/server_addon/maya/server/settings/main.py +++ b/server_addon/maya/server/settings/main.py @@ -1,5 +1,9 @@ -from pydantic import Field, validator -from ayon_server.settings import BaseSettingsModel, ensure_unique_names +from pydantic import validator +from ayon_server.settings import ( + BaseSettingsModel, + SettingsField, + ensure_unique_names, +) from .imageio import ImageIOSettings, DEFAULT_IMAGEIO_SETTINGS from .maya_dirmap import MayaDirmapModel, DEFAULT_MAYA_DIRMAP_SETTINGS from .include_handles import IncludeHandlesModel, DEFAULT_INCLUDE_HANDLES @@ -19,44 +23,46 @@ from .templated_workfile_settings import ( class ExtMappingItemModel(BaseSettingsModel): _layout = "compact" - name: str = Field(title="Product type") - value: str = Field(title="Extension") + name: str = SettingsField(title="Product type") + value: str = SettingsField(title="Extension") class MayaSettings(BaseSettingsModel): """Maya Project Settings.""" - open_workfile_post_initialization: bool = Field( + open_workfile_post_initialization: bool = SettingsField( True, title="Open Workfile Post Initialization") - explicit_plugins_loading: ExplicitPluginsLoadingModel = Field( + explicit_plugins_loading: ExplicitPluginsLoadingModel = SettingsField( default_factory=ExplicitPluginsLoadingModel, title="Explicit Plugins Loading") - imageio: ImageIOSettings = Field( + imageio: ImageIOSettings = SettingsField( default_factory=ImageIOSettings, title="Color Management (imageio)") - mel_workspace: str = Field(title="Maya MEL Workspace", widget="textarea") - ext_mapping: list[ExtMappingItemModel] = Field( + mel_workspace: str = SettingsField( + title="Maya MEL Workspace", widget="textarea" + ) + ext_mapping: list[ExtMappingItemModel] = SettingsField( default_factory=list, title="Extension Mapping") - maya_dirmap: MayaDirmapModel = Field( + maya_dirmap: MayaDirmapModel = SettingsField( default_factory=MayaDirmapModel, title="Maya dirmap Settings") - include_handles: IncludeHandlesModel = Field( + include_handles: IncludeHandlesModel = SettingsField( default_factory=IncludeHandlesModel, title="Include/Exclude Handles in default playback & render range" ) - scriptsmenu: ScriptsmenuModel = Field( + scriptsmenu: ScriptsmenuModel = SettingsField( default_factory=ScriptsmenuModel, title="Scriptsmenu Settings" ) - render_settings: RenderSettingsModel = Field( + render_settings: RenderSettingsModel = SettingsField( default_factory=RenderSettingsModel, title="Render Settings") - create: CreatorsModel = Field( + create: CreatorsModel = SettingsField( default_factory=CreatorsModel, title="Creators") - publish: PublishersModel = Field( + publish: PublishersModel = SettingsField( default_factory=PublishersModel, title="Publishers") - load: LoadersModel = Field( + load: LoadersModel = SettingsField( default_factory=LoadersModel, title="Loaders") - workfile_build: ProfilesModel = Field( + workfile_build: ProfilesModel = SettingsField( default_factory=ProfilesModel, title="Workfile Build Settings") - templated_workfile_build: TemplatedProfilesModel = Field( + templated_workfile_build: TemplatedProfilesModel = SettingsField( default_factory=TemplatedProfilesModel, title="Templated Workfile Build Settings") diff --git a/server_addon/maya/server/settings/maya_dirmap.py b/server_addon/maya/server/settings/maya_dirmap.py index 243261dc87..f68028cd79 100644 --- a/server_addon/maya/server/settings/maya_dirmap.py +++ b/server_addon/maya/server/settings/maya_dirmap.py @@ -1,14 +1,12 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class MayaDirmapPathsSubmodel(BaseSettingsModel): _layout = "compact" - source_path: list[str] = Field( + source_path: list[str] = SettingsField( default_factory=list, title="Source Paths" ) - destination_path: list[str] = Field( + destination_path: list[str] = SettingsField( default_factory=list, title="Destination Paths" ) @@ -18,13 +16,13 @@ class MayaDirmapModel(BaseSettingsModel): # _layout = "expanded" _isGroup: bool = True - enabled: bool = Field(title="enabled") + enabled: bool = SettingsField(title="enabled") # Use ${} placeholder instead of absolute value of a root in # referenced filepaths. - use_env_var_as_root: bool = Field( + use_env_var_as_root: bool = SettingsField( title="Use env var placeholder in referenced paths" ) - paths: MayaDirmapPathsSubmodel = Field( + paths: MayaDirmapPathsSubmodel = SettingsField( default_factory=MayaDirmapPathsSubmodel, title="Dirmap Paths" ) diff --git a/server_addon/maya/server/settings/publish_playblast.py b/server_addon/maya/server/settings/publish_playblast.py index 0abc9f7110..0461a18cc8 100644 --- a/server_addon/maya/server/settings/publish_playblast.py +++ b/server_addon/maya/server/settings/publish_playblast.py @@ -1,7 +1,8 @@ -from pydantic import Field, validator +from pydantic import validator from ayon_server.settings import ( BaseSettingsModel, + SettingsField, ensure_unique_names, task_types_enum, ) @@ -43,36 +44,40 @@ def plugin_objects_default(): class CodecSetting(BaseSettingsModel): _layout = "expanded" - compression: str = Field("png", title="Encoding") - format: str = Field("image", title="Format") - quality: int = Field(95, title="Quality", ge=0, le=100) + compression: str = SettingsField("png", title="Encoding") + format: str = SettingsField("image", title="Format") + quality: int = SettingsField(95, title="Quality", ge=0, le=100) class DisplayOptionsSetting(BaseSettingsModel): _layout = "expanded" - override_display: bool = Field(True, title="Override display options") - background: ColorRGBA_uint8 = Field( + override_display: bool = SettingsField( + True, title="Override display options" + ) + background: ColorRGBA_uint8 = SettingsField( (125, 125, 125, 1.0), title="Background Color" ) - displayGradient: bool = Field(True, title="Display background gradient") - backgroundTop: ColorRGBA_uint8 = Field( + displayGradient: bool = SettingsField( + True, title="Display background gradient" + ) + backgroundTop: ColorRGBA_uint8 = SettingsField( (125, 125, 125, 1.0), title="Background Top" ) - backgroundBottom: ColorRGBA_uint8 = Field( + backgroundBottom: ColorRGBA_uint8 = SettingsField( (125, 125, 125, 1.0), title="Background Bottom" ) class GenericSetting(BaseSettingsModel): _layout = "expanded" - isolate_view: bool = Field(True, title="Isolate View") - off_screen: bool = Field(True, title="Off Screen") - pan_zoom: bool = Field(False, title="2D Pan/Zoom") + isolate_view: bool = SettingsField(True, title="Isolate View") + off_screen: bool = SettingsField(True, title="Off Screen") + pan_zoom: bool = SettingsField(False, title="2D Pan/Zoom") class RendererSetting(BaseSettingsModel): _layout = "expanded" - rendererName: str = Field( + rendererName: str = SettingsField( "vp2Renderer", enum_resolver=renderer_enum, title="Renderer name" @@ -81,100 +86,112 @@ class RendererSetting(BaseSettingsModel): class ResolutionSetting(BaseSettingsModel): _layout = "expanded" - width: int = Field(0, title="Width") - height: int = Field(0, title="Height") + width: int = SettingsField(0, title="Width") + height: int = SettingsField(0, title="Height") class PluginObjectsModel(BaseSettingsModel): - name: str = Field("", title="Name") - value: bool = Field(True, title="Enabled") + name: str = SettingsField("", title="Name") + value: bool = SettingsField(True, title="Enabled") class ViewportOptionsSetting(BaseSettingsModel): - override_viewport_options: bool = Field( + override_viewport_options: bool = SettingsField( True, title="Override viewport options" ) - displayLights: str = Field( + displayLights: str = SettingsField( "default", enum_resolver=displayLights_enum, title="Display Lights" ) - displayTextures: bool = Field(True, title="Display Textures") - textureMaxResolution: int = Field(1024, title="Texture Clamp Resolution") - renderDepthOfField: bool = Field( + displayTextures: bool = SettingsField(True, title="Display Textures") + textureMaxResolution: int = SettingsField( + 1024, title="Texture Clamp Resolution" + ) + renderDepthOfField: bool = SettingsField( True, title="Depth of Field", section="Depth of Field" ) - shadows: bool = Field(True, title="Display Shadows") - twoSidedLighting: bool = Field(True, title="Two Sided Lighting") - lineAAEnable: bool = Field( + shadows: bool = SettingsField(True, title="Display Shadows") + twoSidedLighting: bool = SettingsField(True, title="Two Sided Lighting") + lineAAEnable: bool = SettingsField( True, title="Enable Anti-Aliasing", section="Anti-Aliasing" ) - multiSample: int = Field(8, title="Anti Aliasing Samples") - loadTextures: bool = Field(False, title="Load Textures") - useDefaultMaterial: bool = Field(False, title="Use Default Material") - wireframeOnShaded: bool = Field(False, title="Wireframe On Shaded") - xray: bool = Field(False, title="X-Ray") - jointXray: bool = Field(False, title="X-Ray Joints") - backfaceCulling: bool = Field(False, title="Backface Culling") - ssaoEnable: bool = Field( + multiSample: int = SettingsField(8, title="Anti Aliasing Samples") + loadTextures: bool = SettingsField(False, title="Load Textures") + useDefaultMaterial: bool = SettingsField( + False, title="Use Default Material" + ) + wireframeOnShaded: bool = SettingsField(False, title="Wireframe On Shaded") + xray: bool = SettingsField(False, title="X-Ray") + jointXray: bool = SettingsField(False, title="X-Ray Joints") + backfaceCulling: bool = SettingsField(False, title="Backface Culling") + ssaoEnable: bool = SettingsField( False, title="Screen Space Ambient Occlusion", section="SSAO" ) - ssaoAmount: int = Field(1, title="SSAO Amount") - ssaoRadius: int = Field(16, title="SSAO Radius") - ssaoFilterRadius: int = Field(16, title="SSAO Filter Radius") - ssaoSamples: int = Field(16, title="SSAO Samples") - fogging: bool = Field(False, title="Enable Hardware Fog", section="Fog") - hwFogFalloff: str = Field( + ssaoAmount: int = SettingsField(1, title="SSAO Amount") + ssaoRadius: int = SettingsField(16, title="SSAO Radius") + ssaoFilterRadius: int = SettingsField(16, title="SSAO Filter Radius") + ssaoSamples: int = SettingsField(16, title="SSAO Samples") + fogging: bool = SettingsField( + False, title="Enable Hardware Fog", section="Fog" + ) + hwFogFalloff: str = SettingsField( "0", enum_resolver=hardware_falloff_enum, title="Hardware Falloff" ) - hwFogDensity: float = Field(0.0, title="Fog Density") - hwFogStart: int = Field(0, title="Fog Start") - hwFogEnd: int = Field(100, title="Fog End") - hwFogAlpha: int = Field(0, title="Fog Alpha") - hwFogColorR: float = Field(1.0, title="Fog Color R") - hwFogColorG: float = Field(1.0, title="Fog Color G") - hwFogColorB: float = Field(1.0, title="Fog Color B") - motionBlurEnable: bool = Field( + hwFogDensity: float = SettingsField(0.0, title="Fog Density") + hwFogStart: int = SettingsField(0, title="Fog Start") + hwFogEnd: int = SettingsField(100, title="Fog End") + hwFogAlpha: int = SettingsField(0, title="Fog Alpha") + hwFogColorR: float = SettingsField(1.0, title="Fog Color R") + hwFogColorG: float = SettingsField(1.0, title="Fog Color G") + hwFogColorB: float = SettingsField(1.0, title="Fog Color B") + motionBlurEnable: bool = SettingsField( False, title="Enable Motion Blur", section="Motion Blur" ) - motionBlurSampleCount: int = Field(8, title="Motion Blur Sample Count") - motionBlurShutterOpenFraction: float = Field( + motionBlurSampleCount: int = SettingsField( + 8, title="Motion Blur Sample Count" + ) + motionBlurShutterOpenFraction: float = SettingsField( 0.2, title="Shutter Open Fraction" ) - cameras: bool = Field(False, title="Cameras", section="Show") - clipGhosts: bool = Field(False, title="Clip Ghosts") - deformers: bool = Field(False, title="Deformers") - dimensions: bool = Field(False, title="Dimensions") - dynamicConstraints: bool = Field(False, title="Dynamic Constraints") - dynamics: bool = Field(False, title="Dynamics") - fluids: bool = Field(False, title="Fluids") - follicles: bool = Field(False, title="Follicles") - greasePencils: bool = Field(False, title="Grease Pencils") - grid: bool = Field(False, title="Grid") - hairSystems: bool = Field(True, title="Hair Systems") - handles: bool = Field(False, title="Handles") - headsUpDisplay: bool = Field(False, title="HUD") - ikHandles: bool = Field(False, title="IK Handles") - imagePlane: bool = Field(True, title="Image Plane") - joints: bool = Field(False, title="Joints") - lights: bool = Field(False, title="Lights") - locators: bool = Field(False, title="Locators") - manipulators: bool = Field(False, title="Manipulators") - motionTrails: bool = Field(False, title="Motion Trails") - nCloths: bool = Field(False, title="nCloths") - nParticles: bool = Field(False, title="nParticles") - nRigids: bool = Field(False, title="nRigids") - controlVertices: bool = Field(False, title="NURBS CVs") - nurbsCurves: bool = Field(False, title="NURBS Curves") - hulls: bool = Field(False, title="NURBS Hulls") - nurbsSurfaces: bool = Field(False, title="NURBS Surfaces") - particleInstancers: bool = Field(False, title="Particle Instancers") - pivots: bool = Field(False, title="Pivots") - planes: bool = Field(False, title="Planes") - pluginShapes: bool = Field(False, title="Plugin Shapes") - polymeshes: bool = Field(True, title="Polygons") - strokes: bool = Field(False, title="Strokes") - subdivSurfaces: bool = Field(False, title="Subdiv Surfaces") - textures: bool = Field(False, title="Texture Placements") - pluginObjects: list[PluginObjectsModel] = Field( + cameras: bool = SettingsField(False, title="Cameras", section="Show") + clipGhosts: bool = SettingsField(False, title="Clip Ghosts") + deformers: bool = SettingsField(False, title="Deformers") + dimensions: bool = SettingsField(False, title="Dimensions") + dynamicConstraints: bool = SettingsField( + False, title="Dynamic Constraints" + ) + dynamics: bool = SettingsField(False, title="Dynamics") + fluids: bool = SettingsField(False, title="Fluids") + follicles: bool = SettingsField(False, title="Follicles") + greasePencils: bool = SettingsField(False, title="Grease Pencils") + grid: bool = SettingsField(False, title="Grid") + hairSystems: bool = SettingsField(True, title="Hair Systems") + handles: bool = SettingsField(False, title="Handles") + headsUpDisplay: bool = SettingsField(False, title="HUD") + ikHandles: bool = SettingsField(False, title="IK Handles") + imagePlane: bool = SettingsField(True, title="Image Plane") + joints: bool = SettingsField(False, title="Joints") + lights: bool = SettingsField(False, title="Lights") + locators: bool = SettingsField(False, title="Locators") + manipulators: bool = SettingsField(False, title="Manipulators") + motionTrails: bool = SettingsField(False, title="Motion Trails") + nCloths: bool = SettingsField(False, title="nCloths") + nParticles: bool = SettingsField(False, title="nParticles") + nRigids: bool = SettingsField(False, title="nRigids") + controlVertices: bool = SettingsField(False, title="NURBS CVs") + nurbsCurves: bool = SettingsField(False, title="NURBS Curves") + hulls: bool = SettingsField(False, title="NURBS Hulls") + nurbsSurfaces: bool = SettingsField(False, title="NURBS Surfaces") + particleInstancers: bool = SettingsField( + False, title="Particle Instancers" + ) + pivots: bool = SettingsField(False, title="Pivots") + planes: bool = SettingsField(False, title="Planes") + pluginShapes: bool = SettingsField(False, title="Plugin Shapes") + polymeshes: bool = SettingsField(True, title="Polygons") + strokes: bool = SettingsField(False, title="Strokes") + subdivSurfaces: bool = SettingsField(False, title="Subdiv Surfaces") + textures: bool = SettingsField(False, title="Texture Placements") + pluginObjects: list[PluginObjectsModel] = SettingsField( default_factory=plugin_objects_default, title="Plugin Objects" ) @@ -186,67 +203,71 @@ class ViewportOptionsSetting(BaseSettingsModel): class CameraOptionsSetting(BaseSettingsModel): - displayGateMask: bool = Field(False, title="Display Gate Mask") - displayResolution: bool = Field(False, title="Display Resolution") - displayFilmGate: bool = Field(False, title="Display Film Gate") - displayFieldChart: bool = Field(False, title="Display Field Chart") - displaySafeAction: bool = Field(False, title="Display Safe Action") - displaySafeTitle: bool = Field(False, title="Display Safe Title") - displayFilmPivot: bool = Field(False, title="Display Film Pivot") - displayFilmOrigin: bool = Field(False, title="Display Film Origin") - overscan: int = Field(1.0, title="Overscan") + displayGateMask: bool = SettingsField(False, title="Display Gate Mask") + displayResolution: bool = SettingsField(False, title="Display Resolution") + displayFilmGate: bool = SettingsField(False, title="Display Film Gate") + displayFieldChart: bool = SettingsField(False, title="Display Field Chart") + displaySafeAction: bool = SettingsField(False, title="Display Safe Action") + displaySafeTitle: bool = SettingsField(False, title="Display Safe Title") + displayFilmPivot: bool = SettingsField(False, title="Display Film Pivot") + displayFilmOrigin: bool = SettingsField(False, title="Display Film Origin") + overscan: int = SettingsField(1.0, title="Overscan") class CapturePresetSetting(BaseSettingsModel): - Codec: CodecSetting = Field( + Codec: CodecSetting = SettingsField( default_factory=CodecSetting, title="Codec", section="Codec") - DisplayOptions: DisplayOptionsSetting = Field( + DisplayOptions: DisplayOptionsSetting = SettingsField( default_factory=DisplayOptionsSetting, title="Display Options", section="Display Options") - Generic: GenericSetting = Field( + Generic: GenericSetting = SettingsField( default_factory=GenericSetting, title="Generic", section="Generic") - Renderer: RendererSetting = Field( + Renderer: RendererSetting = SettingsField( default_factory=RendererSetting, title="Renderer", section="Renderer") - Resolution: ResolutionSetting = Field( + Resolution: ResolutionSetting = SettingsField( default_factory=ResolutionSetting, title="Resolution", section="Resolution") - ViewportOptions: ViewportOptionsSetting = Field( + ViewportOptions: ViewportOptionsSetting = SettingsField( default_factory=ViewportOptionsSetting, title="Viewport Options") - CameraOptions: CameraOptionsSetting = Field( + CameraOptions: CameraOptionsSetting = SettingsField( default_factory=CameraOptionsSetting, title="Camera Options") class ProfilesModel(BaseSettingsModel): _layout = "expanded" - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - task_names: list[str] = Field(default_factory=list, title="Task names") - product_names: list[str] = Field(default_factory=list, title="Products names") - capture_preset: CapturePresetSetting = Field( + task_names: list[str] = SettingsField( + default_factory=list, title="Task names" + ) + product_names: list[str] = SettingsField( + default_factory=list, title="Products names" + ) + capture_preset: CapturePresetSetting = SettingsField( default_factory=CapturePresetSetting, title="Capture Preset" ) class ExtractPlayblastSetting(BaseSettingsModel): - capture_preset: CapturePresetSetting = Field( + capture_preset: CapturePresetSetting = SettingsField( default_factory=CapturePresetSetting, title="DEPRECATED! Please use \"Profiles\" below. Capture Preset" ) - profiles: list[ProfilesModel] = Field( + profiles: list[ProfilesModel] = SettingsField( default_factory=list, title="Profiles" ) diff --git a/server_addon/maya/server/settings/publishers.py b/server_addon/maya/server/settings/publishers.py index e823efe681..3a6de2eb44 100644 --- a/server_addon/maya/server/settings/publishers.py +++ b/server_addon/maya/server/settings/publishers.py @@ -1,7 +1,8 @@ import json -from pydantic import Field, validator +from pydantic import validator from ayon_server.settings import ( BaseSettingsModel, + SettingsField, MultiplatformPathModel, ensure_unique_names, ) @@ -35,9 +36,9 @@ def angular_unit_enum(): class BasicValidateModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") + enabled: bool = SettingsField(title="Enabled") + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") class ValidateMeshUVSetMap1Model(BasicValidateModel): @@ -51,22 +52,24 @@ class ValidateNoAnimationModel(BasicValidateModel): class ValidateRigOutSetNodeIdsModel(BaseSettingsModel): - enabled: bool = Field(title="ValidateSkinclusterDeformerSet") - optional: bool = Field(title="Optional") - allow_history_only: bool = Field(title="Allow history only") + enabled: bool = SettingsField(title="ValidateSkinclusterDeformerSet") + optional: bool = SettingsField(title="Optional") + allow_history_only: bool = SettingsField(title="Allow history only") class ValidateModelNameModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - database: bool = Field(title="Use database shader name definitions") - material_file: MultiplatformPathModel = Field( + enabled: bool = SettingsField(title="Enabled") + database: bool = SettingsField( + title="Use database shader name definitions" + ) + material_file: MultiplatformPathModel = SettingsField( default_factory=MultiplatformPathModel, title="Material File", description=( "Path to material file defining list of material names to check." ) ) - regex: str = Field( + regex: str = SettingsField( "(.*)_(\\d)*_(?P.*)_(GEO)", title="Validation regex", description=( @@ -74,7 +77,7 @@ class ValidateModelNameModel(BaseSettingsModel): " named capturing groups:(?P.*) for Asset name" ) ) - top_level_regex: str = Field( + top_level_regex: str = SettingsField( ".*_GRP", title="Top level group name regex", description=( @@ -85,15 +88,15 @@ class ValidateModelNameModel(BaseSettingsModel): class ValidateModelContentModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - optional: bool = Field(title="Optional") - validate_top_group: bool = Field(title="Validate one top group") + enabled: bool = SettingsField(title="Enabled") + optional: bool = SettingsField(title="Optional") + validate_top_group: bool = SettingsField(title="Validate one top group") class ValidateTransformNamingSuffixModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - optional: bool = Field(title="Optional") - SUFFIX_NAMING_TABLE: str = Field( + enabled: bool = SettingsField(title="Enabled") + optional: bool = SettingsField(title="Optional") + SUFFIX_NAMING_TABLE: str = SettingsField( "{}", title="Suffix Naming Tables", widget="textarea", @@ -118,34 +121,34 @@ class ValidateTransformNamingSuffixModel(BaseSettingsModel): "The text can't be parsed as json object" ) return value - ALLOW_IF_NOT_IN_SUFFIX_TABLE: bool = Field( + ALLOW_IF_NOT_IN_SUFFIX_TABLE: bool = SettingsField( title="Allow if suffix not in table" ) class CollectMayaRenderModel(BaseSettingsModel): - sync_workfile_version: bool = Field( + sync_workfile_version: bool = SettingsField( title="Sync render version with workfile" ) class CollectFbxAnimationModel(BaseSettingsModel): - enabled: bool = Field(title="Collect Fbx Animation") + enabled: bool = SettingsField(title="Collect Fbx Animation") class CollectFbxCameraModel(BaseSettingsModel): - enabled: bool = Field(title="CollectFbxCamera") + enabled: bool = SettingsField(title="CollectFbxCamera") class CollectGLTFModel(BaseSettingsModel): - enabled: bool = Field(title="CollectGLTF") + enabled: bool = SettingsField(title="CollectGLTF") class ValidateFrameRangeModel(BaseSettingsModel): - enabled: bool = Field(title="ValidateFrameRange") - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") - exclude_product_types: list[str] = Field( + enabled: bool = SettingsField(title="ValidateFrameRange") + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") + exclude_product_types: list[str] = SettingsField( default_factory=list, title="Exclude product types" ) @@ -155,15 +158,18 @@ class ValidateShaderNameModel(BaseSettingsModel): """ Shader name regex can use named capture group asset to validate against current asset name. """ - enabled: bool = Field(title="ValidateShaderName") - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") - regex: str = Field("(?P.*)_(.*)_SHD", title="Validation regex") + enabled: bool = SettingsField(title="ValidateShaderName") + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") + regex: str = SettingsField( + "(?P.*)_(.*)_SHD", + title="Validation regex" + ) class ValidateAttributesModel(BaseSettingsModel): - enabled: bool = Field(title="ValidateAttributes") - attributes: str = Field( + enabled: bool = SettingsField(title="ValidateAttributes") + attributes: str = SettingsField( "{}", title="Attributes", widget="textarea") @validator("attributes") @@ -184,46 +190,50 @@ class ValidateAttributesModel(BaseSettingsModel): class ValidateLoadedPluginModel(BaseSettingsModel): - enabled: bool = Field(title="ValidateLoadedPlugin") - optional: bool = Field(title="Optional") - whitelist_native_plugins: bool = Field( + enabled: bool = SettingsField(title="ValidateLoadedPlugin") + optional: bool = SettingsField(title="Optional") + whitelist_native_plugins: bool = SettingsField( title="Whitelist Maya Native Plugins" ) - authorized_plugins: list[str] = Field( + authorized_plugins: list[str] = SettingsField( default_factory=list, title="Authorized plugins" ) class ValidateMayaUnitsModel(BaseSettingsModel): - enabled: bool = Field(title="ValidateMayaUnits") - optional: bool = Field(title="Optional") - validate_linear_units: bool = Field(title="Validate linear units") - linear_units: str = Field( + enabled: bool = SettingsField(title="ValidateMayaUnits") + optional: bool = SettingsField(title="Optional") + validate_linear_units: bool = SettingsField(title="Validate linear units") + linear_units: str = SettingsField( enum_resolver=linear_unit_enum, title="Linear Units" ) - validate_angular_units: bool = Field(title="Validate angular units") - angular_units: str = Field( + validate_angular_units: bool = SettingsField( + title="Validate angular units" + ) + angular_units: str = SettingsField( enum_resolver=angular_unit_enum, title="Angular units" ) - validate_fps: bool = Field(title="Validate fps") + validate_fps: bool = SettingsField(title="Validate fps") class ValidateUnrealStaticMeshNameModel(BaseSettingsModel): - enabled: bool = Field(title="ValidateUnrealStaticMeshName") - optional: bool = Field(title="Optional") - validate_mesh: bool = Field(title="Validate mesh names") - validate_collision: bool = Field(title="Validate collison names") + enabled: bool = SettingsField(title="ValidateUnrealStaticMeshName") + optional: bool = SettingsField(title="Optional") + validate_mesh: bool = SettingsField(title="Validate mesh names") + validate_collision: bool = SettingsField(title="Validate collison names") class ValidateCycleErrorModel(BaseSettingsModel): - enabled: bool = Field(title="ValidateCycleError") - optional: bool = Field(title="Optional") - families: list[str] = Field(default_factory=list, title="Families") + enabled: bool = SettingsField(title="ValidateCycleError") + optional: bool = SettingsField(title="Optional") + families: list[str] = SettingsField( + default_factory=list, title="Families" + ) class ValidatePluginPathAttributesAttrModel(BaseSettingsModel): - name: str = Field(title="Node type") - value: str = Field(title="Attribute") + name: str = SettingsField(title="Node type") + value: str = SettingsField(title="Attribute") class ValidatePluginPathAttributesModel(BaseSettingsModel): @@ -234,9 +244,9 @@ class ValidatePluginPathAttributesModel(BaseSettingsModel): """ enabled: bool = True - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") - attribute: list[ValidatePluginPathAttributesAttrModel] = Field( + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") + attribute: list[ValidatePluginPathAttributesAttrModel] = SettingsField( default_factory=list, title="File Attribute" ) @@ -250,66 +260,68 @@ class ValidatePluginPathAttributesModel(BaseSettingsModel): # Validate Render Setting class RendererAttributesModel(BaseSettingsModel): _layout = "compact" - type: str = Field(title="Type") - value: str = Field(title="Value") + type: str = SettingsField(title="Type") + value: str = SettingsField(title="Value") class ValidateRenderSettingsModel(BaseSettingsModel): - arnold_render_attributes: list[RendererAttributesModel] = Field( + arnold_render_attributes: list[RendererAttributesModel] = SettingsField( default_factory=list, title="Arnold Render Attributes") - vray_render_attributes: list[RendererAttributesModel] = Field( + vray_render_attributes: list[RendererAttributesModel] = SettingsField( default_factory=list, title="VRay Render Attributes") - redshift_render_attributes: list[RendererAttributesModel] = Field( + redshift_render_attributes: list[RendererAttributesModel] = SettingsField( default_factory=list, title="Redshift Render Attributes") - renderman_render_attributes: list[RendererAttributesModel] = Field( + renderman_render_attributes: list[RendererAttributesModel] = SettingsField( default_factory=list, title="Renderman Render Attributes") class BasicValidateModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") + enabled: bool = SettingsField(title="Enabled") + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") class ValidateCameraContentsModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - optional: bool = Field(title="Optional") - validate_shapes: bool = Field(title="Validate presence of shapes") + enabled: bool = SettingsField(title="Enabled") + optional: bool = SettingsField(title="Optional") + validate_shapes: bool = SettingsField(title="Validate presence of shapes") class ExtractProxyAlembicModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - families: list[str] = Field( + enabled: bool = SettingsField(title="Enabled") + families: list[str] = SettingsField( default_factory=list, title="Families") class ExtractAlembicModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - families: list[str] = Field( + enabled: bool = SettingsField(title="Enabled") + families: list[str] = SettingsField( default_factory=list, title="Families") class ExtractObjModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - optional: bool = Field(title="Optional") + enabled: bool = SettingsField(title="Enabled") + optional: bool = SettingsField(title="Optional") class ExtractMayaSceneRawModel(BaseSettingsModel): """Add loaded instances to those published families:""" - enabled: bool = Field(title="ExtractMayaSceneRaw") - add_for_families: list[str] = Field(default_factory=list, title="Families") + enabled: bool = SettingsField(title="ExtractMayaSceneRaw") + add_for_families: list[str] = SettingsField( + default_factory=list, title="Families" + ) class ExtractCameraAlembicModel(BaseSettingsModel): """ List of attributes that will be added to the baked alembic camera. Needs to be written in python list syntax. """ - enabled: bool = Field(title="ExtractCameraAlembic") - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") - bake_attributes: str = Field( + enabled: bool = SettingsField(title="ExtractCameraAlembic") + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") + bake_attributes: str = SettingsField( "[]", title="Base Attributes", widget="textarea" ) @@ -332,17 +344,19 @@ class ExtractCameraAlembicModel(BaseSettingsModel): class ExtractGLBModel(BaseSettingsModel): enabled: bool = True - active: bool = Field(title="Active") - ogsfx_path: str = Field(title="GLSL Shader Directory") + active: bool = SettingsField(title="Active") + ogsfx_path: str = SettingsField(title="GLSL Shader Directory") class ExtractLookArgsModel(BaseSettingsModel): - argument: str = Field(title="Argument") - parameters: list[str] = Field(default_factory=list, title="Parameters") + argument: str = SettingsField(title="Argument") + parameters: list[str] = SettingsField( + default_factory=list, title="Parameters" + ) class ExtractLookModel(BaseSettingsModel): - maketx_arguments: list[ExtractLookArgsModel] = Field( + maketx_arguments: list[ExtractLookArgsModel] = SettingsField( default_factory=list, title="Extra arguments for maketx command line" ) @@ -350,423 +364,437 @@ class ExtractLookModel(BaseSettingsModel): class ExtractGPUCacheModel(BaseSettingsModel): enabled: bool = True - families: list[str] = Field(default_factory=list, title="Families") - step: float = Field(1.0, ge=1.0, title="Step") - stepSave: int = Field(1, ge=1, title="Step Save") - optimize: bool = Field(title="Optimize Hierarchy") - optimizationThreshold: int = Field(1, ge=1, title="Optimization Threshold") - optimizeAnimationsForMotionBlur: bool = Field( + families: list[str] = SettingsField(default_factory=list, title="Families") + step: float = SettingsField(1.0, ge=1.0, title="Step") + stepSave: int = SettingsField(1, ge=1, title="Step Save") + optimize: bool = SettingsField(title="Optimize Hierarchy") + optimizationThreshold: int = SettingsField( + 1, ge=1, title="Optimization Threshold" + ) + optimizeAnimationsForMotionBlur: bool = SettingsField( title="Optimize Animations For Motion Blur" ) - writeMaterials: bool = Field(title="Write Materials") - useBaseTessellation: bool = Field(title="User Base Tesselation") + writeMaterials: bool = SettingsField(title="Write Materials") + useBaseTessellation: bool = SettingsField(title="User Base Tesselation") class PublishersModel(BaseSettingsModel): - CollectMayaRender: CollectMayaRenderModel = Field( + CollectMayaRender: CollectMayaRenderModel = SettingsField( default_factory=CollectMayaRenderModel, title="Collect Render Layers", section="Collectors" ) - CollectFbxAnimation: CollectFbxAnimationModel = Field( + CollectFbxAnimation: CollectFbxAnimationModel = SettingsField( default_factory=CollectFbxAnimationModel, title="Collect FBX Animation", ) - CollectFbxCamera: CollectFbxCameraModel = Field( + CollectFbxCamera: CollectFbxCameraModel = SettingsField( default_factory=CollectFbxCameraModel, title="Collect Camera for FBX export", ) - CollectGLTF: CollectGLTFModel = Field( + CollectGLTF: CollectGLTFModel = SettingsField( default_factory=CollectGLTFModel, title="Collect Assets for GLB/GLTF export" ) - ValidateInstanceInContext: BasicValidateModel = Field( + ValidateInstanceInContext: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Instance In Context", section="Validators" ) - ValidateContainers: BasicValidateModel = Field( + ValidateContainers: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Containers" ) - ValidateFrameRange: ValidateFrameRangeModel = Field( + ValidateFrameRange: ValidateFrameRangeModel = SettingsField( default_factory=ValidateFrameRangeModel, title="Validate Frame Range" ) - ValidateShaderName: ValidateShaderNameModel = Field( + ValidateShaderName: ValidateShaderNameModel = SettingsField( default_factory=ValidateShaderNameModel, title="Validate Shader Name" ) - ValidateShadingEngine: BasicValidateModel = Field( + ValidateShadingEngine: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Look Shading Engine Naming" ) - ValidateMayaColorSpace: BasicValidateModel = Field( + ValidateMayaColorSpace: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Colorspace" ) - ValidateAttributes: ValidateAttributesModel = Field( + ValidateAttributes: ValidateAttributesModel = SettingsField( default_factory=ValidateAttributesModel, title="Validate Attributes" ) - ValidateLoadedPlugin: ValidateLoadedPluginModel = Field( + ValidateLoadedPlugin: ValidateLoadedPluginModel = SettingsField( default_factory=ValidateLoadedPluginModel, title="Validate Loaded Plugin" ) - ValidateMayaUnits: ValidateMayaUnitsModel = Field( + ValidateMayaUnits: ValidateMayaUnitsModel = SettingsField( default_factory=ValidateMayaUnitsModel, title="Validate Maya Units" ) - ValidateUnrealStaticMeshName: ValidateUnrealStaticMeshNameModel = Field( - default_factory=ValidateUnrealStaticMeshNameModel, - title="Validate Unreal Static Mesh Name" + ValidateUnrealStaticMeshName: ValidateUnrealStaticMeshNameModel = ( + SettingsField( + default_factory=ValidateUnrealStaticMeshNameModel, + title="Validate Unreal Static Mesh Name" + ) ) - ValidateCycleError: ValidateCycleErrorModel = Field( + ValidateCycleError: ValidateCycleErrorModel = SettingsField( default_factory=ValidateCycleErrorModel, title="Validate Cycle Error" ) - ValidatePluginPathAttributes: ValidatePluginPathAttributesModel = Field( - default_factory=ValidatePluginPathAttributesModel, - title="Plug-in Path Attributes" + ValidatePluginPathAttributes: ValidatePluginPathAttributesModel = ( + SettingsField( + default_factory=ValidatePluginPathAttributesModel, + title="Plug-in Path Attributes" + ) ) - ValidateRenderSettings: ValidateRenderSettingsModel = Field( + ValidateRenderSettings: ValidateRenderSettingsModel = SettingsField( default_factory=ValidateRenderSettingsModel, title="Validate Render Settings" ) - ValidateResolution: BasicValidateModel = Field( + ValidateResolution: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Resolution Setting" ) - ValidateCurrentRenderLayerIsRenderable: BasicValidateModel = Field( - default_factory=BasicValidateModel, - title="Validate Current Render Layer Has Renderable Camera" + ValidateCurrentRenderLayerIsRenderable: BasicValidateModel = ( + SettingsField( + default_factory=BasicValidateModel, + title="Validate Current Render Layer Has Renderable Camera" + ) ) - ValidateGLSLMaterial: BasicValidateModel = Field( + ValidateGLSLMaterial: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate GLSL Material" ) - ValidateGLSLPlugin: BasicValidateModel = Field( + ValidateGLSLPlugin: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate GLSL Plugin" ) - ValidateRenderImageRule: BasicValidateModel = Field( + ValidateRenderImageRule: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Render Image Rule (Workspace)" ) - ValidateRenderNoDefaultCameras: BasicValidateModel = Field( + ValidateRenderNoDefaultCameras: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate No Default Cameras Renderable" ) - ValidateRenderSingleCamera: BasicValidateModel = Field( + ValidateRenderSingleCamera: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Render Single Camera " ) - ValidateRenderLayerAOVs: BasicValidateModel = Field( + ValidateRenderLayerAOVs: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Render Passes/AOVs Are Registered" ) - ValidateStepSize: BasicValidateModel = Field( + ValidateStepSize: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Step Size" ) - ValidateVRayDistributedRendering: BasicValidateModel = Field( + ValidateVRayDistributedRendering: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="VRay Distributed Rendering" ) - ValidateVrayReferencedAOVs: BasicValidateModel = Field( + ValidateVrayReferencedAOVs: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="VRay Referenced AOVs" ) - ValidateVRayTranslatorEnabled: BasicValidateModel = Field( + ValidateVRayTranslatorEnabled: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="VRay Translator Settings" ) - ValidateVrayProxy: BasicValidateModel = Field( + ValidateVrayProxy: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="VRay Proxy Settings" ) - ValidateVrayProxyMembers: BasicValidateModel = Field( + ValidateVrayProxyMembers: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="VRay Proxy Members" ) - ValidateYetiRenderScriptCallbacks: BasicValidateModel = Field( + ValidateYetiRenderScriptCallbacks: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Yeti Render Script Callbacks" ) - ValidateYetiRigCacheState: BasicValidateModel = Field( + ValidateYetiRigCacheState: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Yeti Rig Cache State" ) - ValidateYetiRigInputShapesInInstance: BasicValidateModel = Field( + ValidateYetiRigInputShapesInInstance: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Yeti Rig Input Shapes In Instance" ) - ValidateYetiRigSettings: BasicValidateModel = Field( + ValidateYetiRigSettings: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Yeti Rig Settings" ) # Model - START - ValidateModelName: ValidateModelNameModel = Field( + ValidateModelName: ValidateModelNameModel = SettingsField( default_factory=ValidateModelNameModel, title="Validate Model Name", section="Model", ) - ValidateModelContent: ValidateModelContentModel = Field( + ValidateModelContent: ValidateModelContentModel = SettingsField( default_factory=ValidateModelContentModel, title="Validate Model Content", ) - ValidateTransformNamingSuffix: ValidateTransformNamingSuffixModel = Field( - default_factory=ValidateTransformNamingSuffixModel, - title="Validate Transform Naming Suffix", + ValidateTransformNamingSuffix: ValidateTransformNamingSuffixModel = ( + SettingsField( + default_factory=ValidateTransformNamingSuffixModel, + title="Validate Transform Naming Suffix", + ) ) - ValidateColorSets: BasicValidateModel = Field( + ValidateColorSets: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Color Sets", ) - ValidateMeshHasOverlappingUVs: BasicValidateModel = Field( + ValidateMeshHasOverlappingUVs: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Mesh Has Overlapping UVs", ) - ValidateMeshArnoldAttributes: BasicValidateModel = Field( + ValidateMeshArnoldAttributes: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Mesh Arnold Attributes", ) - ValidateMeshShaderConnections: BasicValidateModel = Field( + ValidateMeshShaderConnections: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Mesh Shader Connections", ) - ValidateMeshSingleUVSet: BasicValidateModel = Field( + ValidateMeshSingleUVSet: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Mesh Single UV Set", ) - ValidateMeshHasUVs: BasicValidateModel = Field( + ValidateMeshHasUVs: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Mesh Has UVs", ) - ValidateMeshLaminaFaces: BasicValidateModel = Field( + ValidateMeshLaminaFaces: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Mesh Lamina Faces", ) - ValidateMeshNgons: BasicValidateModel = Field( + ValidateMeshNgons: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Mesh Ngons", ) - ValidateMeshNonManifold: BasicValidateModel = Field( + ValidateMeshNonManifold: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Mesh Non-Manifold", ) - ValidateMeshNoNegativeScale: BasicValidateModel = Field( + ValidateMeshNoNegativeScale: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Mesh No Negative Scale", ) - ValidateMeshNonZeroEdgeLength: BasicValidateModel = Field( + ValidateMeshNonZeroEdgeLength: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Mesh Edge Length Non Zero", ) - ValidateMeshNormalsUnlocked: BasicValidateModel = Field( + ValidateMeshNormalsUnlocked: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Mesh Normals Unlocked", ) - ValidateMeshUVSetMap1: ValidateMeshUVSetMap1Model = Field( + ValidateMeshUVSetMap1: ValidateMeshUVSetMap1Model = SettingsField( default_factory=ValidateMeshUVSetMap1Model, title="Validate Mesh UV Set Map 1", ) - ValidateMeshVerticesHaveEdges: BasicValidateModel = Field( + ValidateMeshVerticesHaveEdges: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Mesh Vertices Have Edges", ) - ValidateNoAnimation: ValidateNoAnimationModel = Field( + ValidateNoAnimation: ValidateNoAnimationModel = SettingsField( default_factory=ValidateNoAnimationModel, title="Validate No Animation", ) - ValidateNoNamespace: BasicValidateModel = Field( + ValidateNoNamespace: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate No Namespace", ) - ValidateNoNullTransforms: BasicValidateModel = Field( + ValidateNoNullTransforms: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate No Null Transforms", ) - ValidateNoUnknownNodes: BasicValidateModel = Field( + ValidateNoUnknownNodes: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate No Unknown Nodes", ) - ValidateNodeNoGhosting: BasicValidateModel = Field( + ValidateNodeNoGhosting: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Node No Ghosting", ) - ValidateShapeDefaultNames: BasicValidateModel = Field( + ValidateShapeDefaultNames: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Shape Default Names", ) - ValidateShapeRenderStats: BasicValidateModel = Field( + ValidateShapeRenderStats: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Shape Render Stats", ) - ValidateShapeZero: BasicValidateModel = Field( + ValidateShapeZero: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Shape Zero", ) - ValidateTransformZero: BasicValidateModel = Field( + ValidateTransformZero: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Transform Zero", ) - ValidateUniqueNames: BasicValidateModel = Field( + ValidateUniqueNames: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Unique Names", ) - ValidateNoVRayMesh: BasicValidateModel = Field( + ValidateNoVRayMesh: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate No V-Ray Proxies (VRayMesh)", ) - ValidateUnrealMeshTriangulated: BasicValidateModel = Field( + ValidateUnrealMeshTriangulated: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate if Mesh is Triangulated", ) - ValidateAlembicVisibleOnly: BasicValidateModel = Field( + ValidateAlembicVisibleOnly: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Alembic Visible Node", ) - ExtractProxyAlembic: ExtractProxyAlembicModel = Field( + ExtractProxyAlembic: ExtractProxyAlembicModel = SettingsField( default_factory=ExtractProxyAlembicModel, title="Extract Proxy Alembic", section="Model Extractors", ) - ExtractAlembic: ExtractAlembicModel = Field( + ExtractAlembic: ExtractAlembicModel = SettingsField( default_factory=ExtractAlembicModel, title="Extract Alembic", ) - ExtractObj: ExtractObjModel = Field( + ExtractObj: ExtractObjModel = SettingsField( default_factory=ExtractObjModel, title="Extract OBJ" ) # Model - END # Rig - START - ValidateRigContents: BasicValidateModel = Field( + ValidateRigContents: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Rig Contents", section="Rig", ) - ValidateRigJointsHidden: BasicValidateModel = Field( + ValidateRigJointsHidden: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Rig Joints Hidden", ) - ValidateRigControllers: BasicValidateModel = Field( + ValidateRigControllers: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Rig Controllers", ) - ValidateAnimatedReferenceRig: BasicValidateModel = Field( + ValidateAnimatedReferenceRig: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Animated Reference Rig", ) - ValidateAnimationContent: BasicValidateModel = Field( + ValidateAnimationContent: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Animation Content", ) - ValidateOutRelatedNodeIds: BasicValidateModel = Field( + ValidateOutRelatedNodeIds: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Animation Out Set Related Node Ids", ) - ValidateRigControllersArnoldAttributes: BasicValidateModel = Field( - default_factory=BasicValidateModel, - title="Validate Rig Controllers (Arnold Attributes)", + ValidateRigControllersArnoldAttributes: BasicValidateModel = ( + SettingsField( + default_factory=BasicValidateModel, + title="Validate Rig Controllers (Arnold Attributes)", + ) ) - ValidateSkeletalMeshHierarchy: BasicValidateModel = Field( + ValidateSkeletalMeshHierarchy: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Skeletal Mesh Top Node", ) - ValidateSkeletonRigContents: BasicValidateModel = Field( + ValidateSkeletonRigContents: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Skeleton Rig Contents" ) - ValidateSkeletonRigControllers: BasicValidateModel = Field( + ValidateSkeletonRigControllers: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Skeleton Rig Controllers" ) - ValidateSkinclusterDeformerSet: BasicValidateModel = Field( + ValidateSkinclusterDeformerSet: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Skincluster Deformer Relationships", ) - ValidateSkeletonRigOutputIds: BasicValidateModel = Field( + ValidateSkeletonRigOutputIds: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Skeleton Rig Output Ids" ) - ValidateSkeletonTopGroupHierarchy: BasicValidateModel = Field( + ValidateSkeletonTopGroupHierarchy: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Skeleton Top Group Hierarchy", ) - ValidateRigOutSetNodeIds: ValidateRigOutSetNodeIdsModel = Field( + ValidateRigOutSetNodeIds: ValidateRigOutSetNodeIdsModel = SettingsField( default_factory=ValidateRigOutSetNodeIdsModel, title="Validate Rig Out Set Node Ids", ) - ValidateSkeletonRigOutSetNodeIds: ValidateRigOutSetNodeIdsModel = Field( - default_factory=ValidateRigOutSetNodeIdsModel, - title="Validate Skeleton Rig Out Set Node Ids", + ValidateSkeletonRigOutSetNodeIds: ValidateRigOutSetNodeIdsModel = ( + SettingsField( + default_factory=ValidateRigOutSetNodeIdsModel, + title="Validate Skeleton Rig Out Set Node Ids", + ) ) # Rig - END - ValidateCameraAttributes: BasicValidateModel = Field( + ValidateCameraAttributes: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Camera Attributes" ) - ValidateAssemblyName: BasicValidateModel = Field( + ValidateAssemblyName: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Assembly Name" ) - ValidateAssemblyNamespaces: BasicValidateModel = Field( + ValidateAssemblyNamespaces: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Assembly Namespaces" ) - ValidateAssemblyModelTransforms: BasicValidateModel = Field( + ValidateAssemblyModelTransforms: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Assembly Model Transforms" ) - ValidateAssRelativePaths: BasicValidateModel = Field( + ValidateAssRelativePaths: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Ass Relative Paths" ) - ValidateInstancerContent: BasicValidateModel = Field( + ValidateInstancerContent: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Instancer Content" ) - ValidateInstancerFrameRanges: BasicValidateModel = Field( + ValidateInstancerFrameRanges: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Instancer Cache Frame Ranges" ) - ValidateNoDefaultCameras: BasicValidateModel = Field( + ValidateNoDefaultCameras: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate No Default Cameras" ) - ValidateUnrealUpAxis: BasicValidateModel = Field( + ValidateUnrealUpAxis: BasicValidateModel = SettingsField( default_factory=BasicValidateModel, title="Validate Unreal Up-Axis Check" ) - ValidateCameraContents: ValidateCameraContentsModel = Field( + ValidateCameraContents: ValidateCameraContentsModel = SettingsField( default_factory=ValidateCameraContentsModel, title="Validate Camera Content" ) - ExtractPlayblast: ExtractPlayblastSetting = Field( + ExtractPlayblast: ExtractPlayblastSetting = SettingsField( default_factory=ExtractPlayblastSetting, title="Extract Playblast Settings", section="Extractors" ) - ExtractMayaSceneRaw: ExtractMayaSceneRawModel = Field( + ExtractMayaSceneRaw: ExtractMayaSceneRawModel = SettingsField( default_factory=ExtractMayaSceneRawModel, title="Maya Scene(Raw)" ) - ExtractCameraAlembic: ExtractCameraAlembicModel = Field( + ExtractCameraAlembic: ExtractCameraAlembicModel = SettingsField( default_factory=ExtractCameraAlembicModel, title="Extract Camera Alembic" ) - ExtractGLB: ExtractGLBModel = Field( + ExtractGLB: ExtractGLBModel = SettingsField( default_factory=ExtractGLBModel, title="Extract GLB" ) - ExtractLook: ExtractLookModel = Field( + ExtractLook: ExtractLookModel = SettingsField( default_factory=ExtractLookModel, title="Extract Look" ) - ExtractGPUCache: ExtractGPUCacheModel = Field( + ExtractGPUCache: ExtractGPUCacheModel = SettingsField( default_factory=ExtractGPUCacheModel, title="Extract GPU Cache", ) diff --git a/server_addon/maya/server/settings/render_settings.py b/server_addon/maya/server/settings/render_settings.py index 75d0994759..577049b42f 100644 --- a/server_addon/maya/server/settings/render_settings.py +++ b/server_addon/maya/server/settings/render_settings.py @@ -1,7 +1,5 @@ """Providing models and values for Maya Render Settings.""" -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField def aov_separators_enum(): @@ -278,22 +276,22 @@ class AdditionalOptionsModel(BaseSettingsModel): """Additional Option""" _layout = "compact" - attribute: str = Field("", title="Attribute name") - value: str = Field("", title="Value") + attribute: str = SettingsField("", title="Attribute name") + value: str = SettingsField("", title="Value") class ArnoldSettingsModel(BaseSettingsModel): - image_prefix: str = Field(title="Image prefix template") - image_format: str = Field( + image_prefix: str = SettingsField(title="Image prefix template") + image_format: str = SettingsField( enum_resolver=arnold_image_format_enum, title="Output Image Format") - multilayer_exr: bool = Field(title="Multilayer (exr)") - tiled: bool = Field(title="Tiled (tif, exr)") - aov_list: list[str] = Field( + multilayer_exr: bool = SettingsField(title="Multilayer (exr)") + tiled: bool = SettingsField(title="Tiled (tif, exr)") + aov_list: list[str] = SettingsField( default_factory=list, enum_resolver=arnold_aov_list_enum, title="AOVs to create" ) - additional_options: list[AdditionalOptionsModel] = Field( + additional_options: list[AdditionalOptionsModel] = SettingsField( default_factory=list, title="Additional Arnold Options", description=( @@ -304,25 +302,25 @@ class ArnoldSettingsModel(BaseSettingsModel): class VraySettingsModel(BaseSettingsModel): - image_prefix: str = Field(title="Image prefix template") + image_prefix: str = SettingsField(title="Image prefix template") # engine was str because of JSON limitation (key must be string) - engine: str = Field( + engine: str = SettingsField( enum_resolver=lambda: [ {"label": "V-Ray", "value": "1"}, {"label": "V-Ray GPU", "value": "2"} ], title="Production Engine" ) - image_format: str = Field( + image_format: str = SettingsField( enum_resolver=vray_image_output_enum, title="Output Image Format" ) - aov_list: list[str] = Field( + aov_list: list[str] = SettingsField( default_factory=list, enum_resolver=vray_aov_list_enum, title="AOVs to create" ) - additional_options: list[AdditionalOptionsModel] = Field( + additional_options: list[AdditionalOptionsModel] = SettingsField( default_factory=list, title="Additional Vray Options", description=( @@ -333,29 +331,29 @@ class VraySettingsModel(BaseSettingsModel): class RedshiftSettingsModel(BaseSettingsModel): - image_prefix: str = Field(title="Image prefix template") + image_prefix: str = SettingsField(title="Image prefix template") # both engines are using the same enumerator, # both were originally str because of JSON limitation. - primary_gi_engine: str = Field( + primary_gi_engine: str = SettingsField( enum_resolver=redshift_engine_enum, title="Primary GI Engine" ) - secondary_gi_engine: str = Field( + secondary_gi_engine: str = SettingsField( enum_resolver=redshift_engine_enum, title="Secondary GI Engine" ) - image_format: str = Field( + image_format: str = SettingsField( enum_resolver=redshift_image_output_enum, title="Output Image Format" ) - multilayer_exr: bool = Field(title="Multilayer (exr)") - force_combine: bool = Field(title="Force combine beauty and AOVs") - aov_list: list[str] = Field( + multilayer_exr: bool = SettingsField(title="Multilayer (exr)") + force_combine: bool = SettingsField(title="Force combine beauty and AOVs") + aov_list: list[str] = SettingsField( default_factory=list, enum_resolver=redshift_aov_list_enum, title="AOVs to create" ) - additional_options: list[AdditionalOptionsModel] = Field( + additional_options: list[AdditionalOptionsModel] = SettingsField( default_factory=list, title="Additional Vray Options", description=( @@ -397,61 +395,61 @@ def renderman_sample_filters_enum(): class RendermanSettingsModel(BaseSettingsModel): - image_prefix: str = Field( + image_prefix: str = SettingsField( "", title="Image prefix template") - image_dir: str = Field( + image_dir: str = SettingsField( "", title="Image Output Directory") - display_filters: list[str] = Field( + display_filters: list[str] = SettingsField( default_factory=list, title="Display Filters", enum_resolver=renderman_display_filters ) - imageDisplay_dir: str = Field( + imageDisplay_dir: str = SettingsField( "", title="Image Display Filter Directory") - sample_filters: list[str] = Field( + sample_filters: list[str] = SettingsField( default_factory=list, title="Sample Filters", enum_resolver=renderman_sample_filters_enum ) - cryptomatte_dir: str = Field( + cryptomatte_dir: str = SettingsField( "", title="Cryptomatte Output Directory") - watermark_dir: str = Field( + watermark_dir: str = SettingsField( "", title="Watermark Filter Directory") - additional_options: list[AdditionalOptionsModel] = Field( + additional_options: list[AdditionalOptionsModel] = SettingsField( default_factory=list, title="Additional Renderer Options" ) class RenderSettingsModel(BaseSettingsModel): - apply_render_settings: bool = Field( + apply_render_settings: bool = SettingsField( title="Apply Render Settings on creation" ) - default_render_image_folder: str = Field( + default_render_image_folder: str = SettingsField( title="Default render image folder" ) - enable_all_lights: bool = Field( + enable_all_lights: bool = SettingsField( title="Include all lights in Render Setup Layers by default" ) - aov_separator: str = Field( + aov_separator: str = SettingsField( "underscore", title="AOV Separator character", enum_resolver=aov_separators_enum ) - reset_current_frame: bool = Field( + reset_current_frame: bool = SettingsField( title="Reset Current Frame") - remove_aovs: bool = Field( + remove_aovs: bool = SettingsField( title="Remove existing AOVs") - arnold_renderer: ArnoldSettingsModel = Field( + arnold_renderer: ArnoldSettingsModel = SettingsField( default_factory=ArnoldSettingsModel, title="Arnold Renderer") - vray_renderer: VraySettingsModel = Field( + vray_renderer: VraySettingsModel = SettingsField( default_factory=VraySettingsModel, title="Vray Renderer") - redshift_renderer: RedshiftSettingsModel = Field( + redshift_renderer: RedshiftSettingsModel = SettingsField( default_factory=RedshiftSettingsModel, title="Redshift Renderer") - renderman_renderer: RendermanSettingsModel = Field( + renderman_renderer: RendermanSettingsModel = SettingsField( default_factory=RendermanSettingsModel, title="Renderman Renderer") diff --git a/server_addon/maya/server/settings/scriptsmenu.py b/server_addon/maya/server/settings/scriptsmenu.py index 4ac2263f7a..d01dff1621 100644 --- a/server_addon/maya/server/settings/scriptsmenu.py +++ b/server_addon/maya/server/settings/scriptsmenu.py @@ -1,24 +1,24 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class ScriptsmenuSubmodel(BaseSettingsModel): """Item Definition""" _isGroup = True - type: str = Field(title="Type") - command: str = Field(title="Command") - sourcetype: str = Field(title="Source Type") - title: str = Field(title="Title") - tooltip: str = Field(title="Tooltip") - tags: list[str] = Field(default_factory=list, title="A list of tags") + type: str = SettingsField(title="Type") + command: str = SettingsField(title="Command") + sourcetype: str = SettingsField(title="Source Type") + title: str = SettingsField(title="Title") + tooltip: str = SettingsField(title="Tooltip") + tags: list[str] = SettingsField( + default_factory=list, title="A list of tags" + ) class ScriptsmenuModel(BaseSettingsModel): _isGroup = True - name: str = Field(title="Menu Name") - definition: list[ScriptsmenuSubmodel] = Field( + name: str = SettingsField(title="Menu Name") + definition: list[ScriptsmenuSubmodel] = SettingsField( default_factory=list, title="Menu Definition", description="Scriptmenu Items Definition" diff --git a/server_addon/maya/server/settings/templated_workfile_settings.py b/server_addon/maya/server/settings/templated_workfile_settings.py index ef81b31a07..1baa2c895c 100644 --- a/server_addon/maya/server/settings/templated_workfile_settings.py +++ b/server_addon/maya/server/settings/templated_workfile_settings.py @@ -1,20 +1,25 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel, task_types_enum +from ayon_server.settings import ( + BaseSettingsModel, + SettingsField, + task_types_enum, +) class WorkfileBuildProfilesModel(BaseSettingsModel): _layout = "expanded" - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - task_names: list[str] = Field(default_factory=list, title="Task names") - path: str = Field("", title="Path to template") + task_names: list[str] = SettingsField( + default_factory=list, title="Task names" + ) + path: str = SettingsField("", title="Path to template") class TemplatedProfilesModel(BaseSettingsModel): - profiles: list[WorkfileBuildProfilesModel] = Field( + profiles: list[WorkfileBuildProfilesModel] = SettingsField( default_factory=list, title="Profiles" ) diff --git a/server_addon/maya/server/settings/workfile_build_settings.py b/server_addon/maya/server/settings/workfile_build_settings.py index 2c7fea85c4..ee0b793405 100644 --- a/server_addon/maya/server/settings/workfile_build_settings.py +++ b/server_addon/maya/server/settings/workfile_build_settings.py @@ -1,38 +1,41 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel, task_types_enum +from ayon_server.settings import ( + BaseSettingsModel, + SettingsField, + task_types_enum, +) class ContextItemModel(BaseSettingsModel): _layout = "expanded" - product_name_filters: list[str] = Field( + product_name_filters: list[str] = SettingsField( default_factory=list, title="Product name Filters") - product_types: list[str] = Field( + product_types: list[str] = SettingsField( default_factory=list, title="Product types") - repre_names: list[str] = Field( + repre_names: list[str] = SettingsField( default_factory=list, title="Repre Names") - loaders: list[str] = Field( + loaders: list[str] = SettingsField( default_factory=list, title="Loaders") class WorkfileSettingModel(BaseSettingsModel): _layout = "expanded" - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, enum_resolver=task_types_enum, title="Task types") - tasks: list[str] = Field( + tasks: list[str] = SettingsField( default_factory=list, title="Task names") - current_context: list[ContextItemModel] = Field( + current_context: list[ContextItemModel] = SettingsField( default_factory=list, title="Current Context") - linked_assets: list[ContextItemModel] = Field( + linked_assets: list[ContextItemModel] = SettingsField( default_factory=list, title="Linked Assets") class ProfilesModel(BaseSettingsModel): - profiles: list[WorkfileSettingModel] = Field( + profiles: list[WorkfileSettingModel] = SettingsField( default_factory=list, title="Profiles" ) diff --git a/server_addon/muster/server/__init__.py b/server_addon/muster/server/__init__.py deleted file mode 100644 index 2cb8943554..0000000000 --- a/server_addon/muster/server/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Type - -from ayon_server.addons import BaseServerAddon - -from .version import __version__ -from .settings import MusterSettings, DEFAULT_VALUES - - -class MusterAddon(BaseServerAddon): - name = "muster" - version = __version__ - title = "Muster" - settings_model: Type[MusterSettings] = MusterSettings - - async def get_default_settings(self): - settings_model_cls = self.get_settings_model() - return settings_model_cls(**DEFAULT_VALUES) diff --git a/server_addon/muster/server/settings.py b/server_addon/muster/server/settings.py deleted file mode 100644 index e37c762870..0000000000 --- a/server_addon/muster/server/settings.py +++ /dev/null @@ -1,41 +0,0 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel - - -class TemplatesMapping(BaseSettingsModel): - _layout = "compact" - name: str = Field(title="Name") - value: int = Field(title="mapping") - - -class MusterSettings(BaseSettingsModel): - enabled: bool = True - MUSTER_REST_URL: str = Field( - "", - title="Muster Rest URL", - scope=["studio"], - ) - - templates_mapping: list[TemplatesMapping] = Field( - default_factory=list, - title="Templates mapping", - ) - - -DEFAULT_VALUES = { - "enabled": False, - "MUSTER_REST_URL": "http://127.0.0.1:9890", - "templates_mapping": [ - {"name": "file_layers", "value": 7}, - {"name": "mentalray", "value": 2}, - {"name": "mentalray_sf", "value": 6}, - {"name": "redshift", "value": 55}, - {"name": "renderman", "value": 29}, - {"name": "software", "value": 1}, - {"name": "software_sf", "value": 5}, - {"name": "turtle", "value": 10}, - {"name": "vector", "value": 4}, - {"name": "vray", "value": 37}, - {"name": "ffmpeg", "value": 48} - ] -} diff --git a/server_addon/muster/server/version.py b/server_addon/muster/server/version.py deleted file mode 100644 index 485f44ac21..0000000000 --- a/server_addon/muster/server/version.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "0.1.1" diff --git a/server_addon/nuke/server/settings/common.py b/server_addon/nuke/server/settings/common.py index 2bc3c9be81..e0ee2b7b3d 100644 --- a/server_addon/nuke/server/settings/common.py +++ b/server_addon/nuke/server/settings/common.py @@ -1,7 +1,6 @@ import json -from pydantic import Field from ayon_server.exceptions import BadRequestException -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.types import ( ColorRGBA_float, ColorRGB_uint8 @@ -27,25 +26,25 @@ def validate_json_dict(value): class Vector2d(BaseSettingsModel): _layout = "compact" - x: float = Field(1.0, title="X") - y: float = Field(1.0, title="Y") + x: float = SettingsField(1.0, title="X") + y: float = SettingsField(1.0, title="Y") class Vector3d(BaseSettingsModel): _layout = "compact" - x: float = Field(1.0, title="X") - y: float = Field(1.0, title="Y") - z: float = Field(1.0, title="Z") + x: float = SettingsField(1.0, title="X") + y: float = SettingsField(1.0, title="Y") + z: float = SettingsField(1.0, title="Z") class Box(BaseSettingsModel): _layout = "compact" - x: float = Field(1.0, title="X") - y: float = Field(1.0, title="Y") - r: float = Field(1.0, title="R") - t: float = Field(1.0, title="T") + x: float = SettingsField(1.0, title="X") + y: float = SettingsField(1.0, title="Y") + r: float = SettingsField(1.0, title="R") + t: float = SettingsField(1.0, title="T") def formatable_knob_type_enum(): @@ -61,12 +60,12 @@ def formatable_knob_type_enum(): class Formatable(BaseSettingsModel): _layout = "compact" - template: str = Field( + template: str = SettingsField( "", placeholder="""{{key}} or {{key}};{{key}}""", title="Template" ) - to_type: str = Field( + to_type: str = SettingsField( "Text", title="To Knob type", enum_resolver=formatable_knob_type_enum, @@ -91,46 +90,46 @@ knob_types_enum = [ class KnobModel(BaseSettingsModel): _layout = "expanded" - type: str = Field( + type: str = SettingsField( title="Type", description="Switch between different knob types", enum_resolver=lambda: knob_types_enum, conditionalEnum=True ) - name: str = Field( + name: str = SettingsField( title="Name", placeholder="Name" ) - text: str = Field("", title="Value") - color_gui: ColorRGB_uint8 = Field( + text: str = SettingsField("", title="Value") + color_gui: ColorRGB_uint8 = SettingsField( (0, 0, 255), title="RGB Uint8", ) - boolean: bool = Field(False, title="Value") - number: int = Field(0, title="Value") - decimal_number: float = Field(0.0, title="Value") - vector_2d: Vector2d = Field( + boolean: bool = SettingsField(False, title="Value") + number: int = SettingsField(0, title="Value") + decimal_number: float = SettingsField(0.0, title="Value") + vector_2d: Vector2d = SettingsField( default_factory=Vector2d, title="Value" ) - vector_3d: Vector3d = Field( + vector_3d: Vector3d = SettingsField( default_factory=Vector3d, title="Value" ) - color: ColorRGBA_float = Field( + color: ColorRGBA_float = SettingsField( (0.0, 0.0, 1.0, 1.0), title="RGBA Float" ) - box: Box = Field( + box: Box = SettingsField( default_factory=Box, title="Value" ) - formatable: Formatable = Field( + formatable: Formatable = SettingsField( default_factory=Formatable, title="Formatable" ) - expression: str = Field( + expression: str = SettingsField( "", title="Expression" ) diff --git a/server_addon/nuke/server/settings/create_plugins.py b/server_addon/nuke/server/settings/create_plugins.py index 80aec51ae0..378d449b0b 100644 --- a/server_addon/nuke/server/settings/create_plugins.py +++ b/server_addon/nuke/server/settings/create_plugins.py @@ -1,6 +1,7 @@ -from pydantic import validator, Field +from pydantic import validator from ayon_server.settings import ( BaseSettingsModel, + SettingsField, ensure_unique_names ) from .common import KnobModel @@ -16,20 +17,20 @@ def instance_attributes_enum(): class PrenodeModel(BaseSettingsModel): - name: str = Field( + name: str = SettingsField( title="Node name" ) - nodeclass: str = Field( + nodeclass: str = SettingsField( "", title="Node class" ) - dependent: str = Field( + dependent: str = SettingsField( "", title="Incoming dependency" ) - knobs: list[KnobModel] = Field( + knobs: list[KnobModel] = SettingsField( default_factory=list, title="Knobs", ) @@ -42,20 +43,20 @@ class PrenodeModel(BaseSettingsModel): class CreateWriteRenderModel(BaseSettingsModel): - temp_rendering_path_template: str = Field( + temp_rendering_path_template: str = SettingsField( title="Temporary rendering path template" ) - default_variants: list[str] = Field( + default_variants: list[str] = SettingsField( title="Default variants", default_factory=list ) - instance_attributes: list[str] = Field( + instance_attributes: list[str] = SettingsField( default_factory=list, enum_resolver=instance_attributes_enum, title="Instance attributes" ) - prenodes: list[PrenodeModel] = Field( + prenodes: list[PrenodeModel] = SettingsField( default_factory=list, title="Preceding nodes", ) @@ -68,20 +69,20 @@ class CreateWriteRenderModel(BaseSettingsModel): class CreateWritePrerenderModel(BaseSettingsModel): - temp_rendering_path_template: str = Field( + temp_rendering_path_template: str = SettingsField( title="Temporary rendering path template" ) - default_variants: list[str] = Field( + default_variants: list[str] = SettingsField( title="Default variants", default_factory=list ) - instance_attributes: list[str] = Field( + instance_attributes: list[str] = SettingsField( default_factory=list, enum_resolver=instance_attributes_enum, title="Instance attributes" ) - prenodes: list[PrenodeModel] = Field( + prenodes: list[PrenodeModel] = SettingsField( default_factory=list, title="Preceding nodes", ) @@ -94,20 +95,20 @@ class CreateWritePrerenderModel(BaseSettingsModel): class CreateWriteImageModel(BaseSettingsModel): - temp_rendering_path_template: str = Field( + temp_rendering_path_template: str = SettingsField( title="Temporary rendering path template" ) - default_variants: list[str] = Field( + default_variants: list[str] = SettingsField( title="Default variants", default_factory=list ) - instance_attributes: list[str] = Field( + instance_attributes: list[str] = SettingsField( default_factory=list, enum_resolver=instance_attributes_enum, title="Instance attributes" ) - prenodes: list[PrenodeModel] = Field( + prenodes: list[PrenodeModel] = SettingsField( default_factory=list, title="Preceding nodes", ) @@ -120,15 +121,15 @@ class CreateWriteImageModel(BaseSettingsModel): class CreatorPluginsSettings(BaseSettingsModel): - CreateWriteRender: CreateWriteRenderModel = Field( + CreateWriteRender: CreateWriteRenderModel = SettingsField( default_factory=CreateWriteRenderModel, title="Create Write Render" ) - CreateWritePrerender: CreateWritePrerenderModel = Field( + CreateWritePrerender: CreateWritePrerenderModel = SettingsField( default_factory=CreateWritePrerenderModel, title="Create Write Prerender" ) - CreateWriteImage: CreateWriteImageModel = Field( + CreateWriteImage: CreateWriteImageModel = SettingsField( default_factory=CreateWriteImageModel, title="Create Write Image" ) diff --git a/server_addon/nuke/server/settings/dirmap.py b/server_addon/nuke/server/settings/dirmap.py index 7e3c443957..3e1bac0739 100644 --- a/server_addon/nuke/server/settings/dirmap.py +++ b/server_addon/nuke/server/settings/dirmap.py @@ -1,14 +1,13 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class DirmapPathsSubmodel(BaseSettingsModel): _layout = "compact" - source_path: list[str] = Field( + source_path: list[str] = SettingsField( default_factory=list, title="Source Paths" ) - destination_path: list[str] = Field( + destination_path: list[str] = SettingsField( default_factory=list, title="Destination Paths" ) @@ -18,8 +17,8 @@ class DirmapSettings(BaseSettingsModel): """Nuke color management project settings.""" _isGroup: bool = True - enabled: bool = Field(title="enabled") - paths: DirmapPathsSubmodel = Field( + enabled: bool = SettingsField(title="enabled") + paths: DirmapPathsSubmodel = SettingsField( default_factory=DirmapPathsSubmodel, title="Dirmap Paths" ) diff --git a/server_addon/nuke/server/settings/general.py b/server_addon/nuke/server/settings/general.py index bcbb183952..d54c725dc1 100644 --- a/server_addon/nuke/server/settings/general.py +++ b/server_addon/nuke/server/settings/general.py @@ -1,23 +1,22 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class MenuShortcut(BaseSettingsModel): """Nuke general project settings.""" - create: str = Field( + create: str = SettingsField( title="Create..." ) - publish: str = Field( + publish: str = SettingsField( title="Publish..." ) - load: str = Field( + load: str = SettingsField( title="Load..." ) - manage: str = Field( + manage: str = SettingsField( title="Manage..." ) - build_workfile: str = Field( + build_workfile: str = SettingsField( title="Build Workfile..." ) @@ -25,7 +24,7 @@ class MenuShortcut(BaseSettingsModel): class GeneralSettings(BaseSettingsModel): """Nuke general project settings.""" - menu: MenuShortcut = Field( + menu: MenuShortcut = SettingsField( default_factory=MenuShortcut, title="Menu Shortcuts", ) diff --git a/server_addon/nuke/server/settings/gizmo.py b/server_addon/nuke/server/settings/gizmo.py index 4cdd614da8..ddb56f891c 100644 --- a/server_addon/nuke/server/settings/gizmo.py +++ b/server_addon/nuke/server/settings/gizmo.py @@ -1,52 +1,52 @@ -from pydantic import Field from ayon_server.settings import ( BaseSettingsModel, + SettingsField, MultiplatformPathModel, MultiplatformPathListModel, ) class SubGizmoItem(BaseSettingsModel): - title: str = Field( + title: str = SettingsField( title="Label" ) - sourcetype: str = Field( + sourcetype: str = SettingsField( title="Type of usage" ) - command: str = Field( + command: str = SettingsField( title="Python command" ) - icon: str = Field( + icon: str = SettingsField( title="Icon Path" ) - shortcut: str = Field( + shortcut: str = SettingsField( title="Hotkey" ) class GizmoDefinitionItem(BaseSettingsModel): - gizmo_toolbar_path: str = Field( + gizmo_toolbar_path: str = SettingsField( title="Gizmo Menu" ) - sub_gizmo_list: list[SubGizmoItem] = Field( + sub_gizmo_list: list[SubGizmoItem] = SettingsField( default_factory=list, title="Sub Gizmo List") class GizmoItem(BaseSettingsModel): """Nuke gizmo item """ - toolbar_menu_name: str = Field( + toolbar_menu_name: str = SettingsField( title="Toolbar Menu Name" ) - gizmo_source_dir: MultiplatformPathListModel = Field( + gizmo_source_dir: MultiplatformPathListModel = SettingsField( default_factory=MultiplatformPathListModel, title="Gizmo Directory Path" ) - toolbar_icon_path: MultiplatformPathModel = Field( + toolbar_icon_path: MultiplatformPathModel = SettingsField( default_factory=MultiplatformPathModel, title="Toolbar Icon Path" ) - gizmo_definition: list[GizmoDefinitionItem] = Field( + gizmo_definition: list[GizmoDefinitionItem] = SettingsField( default_factory=list, title="Gizmo Definition") diff --git a/server_addon/nuke/server/settings/imageio.py b/server_addon/nuke/server/settings/imageio.py index 19ad5ff24a..1b84457133 100644 --- a/server_addon/nuke/server/settings/imageio.py +++ b/server_addon/nuke/server/settings/imageio.py @@ -1,7 +1,8 @@ from typing import Literal -from pydantic import validator, Field +from pydantic import validator from ayon_server.settings import ( BaseSettingsModel, + SettingsField, ensure_unique_names, ) @@ -10,17 +11,17 @@ from .common import KnobModel class NodesModel(BaseSettingsModel): _layout = "expanded" - plugins: list[str] = Field( + plugins: list[str] = SettingsField( default_factory=list, title="Used in plugins" ) - nuke_node_class: str = Field( + nuke_node_class: str = SettingsField( title="Nuke Node Class", ) class RequiredNodesModel(NodesModel): - knobs: list[KnobModel] = Field( + knobs: list[KnobModel] = SettingsField( default_factory=list, title="Knobs", ) @@ -33,12 +34,12 @@ class RequiredNodesModel(NodesModel): class OverrideNodesModel(NodesModel): - subsets: list[str] = Field( + subsets: list[str] = SettingsField( default_factory=list, title="Subsets" ) - knobs: list[KnobModel] = Field( + knobs: list[KnobModel] = SettingsField( default_factory=list, title="Knobs", ) @@ -51,11 +52,11 @@ class OverrideNodesModel(NodesModel): class NodesSetting(BaseSettingsModel): - required_nodes: list[RequiredNodesModel] = Field( + required_nodes: list[RequiredNodesModel] = SettingsField( title="Plugin required", default_factory=list ) - override_nodes: list[OverrideNodesModel] = Field( + override_nodes: list[OverrideNodesModel] = SettingsField( title="Plugin's node overrides", default_factory=list ) @@ -82,21 +83,21 @@ def ocio_configs_switcher_enum(): class WorkfileColorspaceSettings(BaseSettingsModel): """Nuke workfile colorspace preset. """ - color_management: Literal["Nuke", "OCIO"] = Field( + color_management: Literal["Nuke", "OCIO"] = SettingsField( title="Color Management Workflow" ) - native_ocio_config: str = Field( + native_ocio_config: str = SettingsField( title="Native OpenColorIO Config", description="Switch between native OCIO configs", enum_resolver=ocio_configs_switcher_enum, conditionalEnum=True ) - working_space: str = Field( + working_space: str = SettingsField( title="Working Space" ) - thumbnail_space: str = Field( + thumbnail_space: str = SettingsField( title="Thumbnail Space" ) @@ -104,44 +105,44 @@ class WorkfileColorspaceSettings(BaseSettingsModel): class ReadColorspaceRulesItems(BaseSettingsModel): _layout = "expanded" - regex: str = Field("", title="Regex expression") - colorspace: str = Field("", title="Colorspace") + regex: str = SettingsField("", title="Regex expression") + colorspace: str = SettingsField("", title="Colorspace") class RegexInputsModel(BaseSettingsModel): - inputs: list[ReadColorspaceRulesItems] = Field( + inputs: list[ReadColorspaceRulesItems] = SettingsField( default_factory=list, title="Inputs" ) class ViewProcessModel(BaseSettingsModel): - viewerProcess: str = Field( + viewerProcess: str = SettingsField( title="Viewer Process Name" ) class ImageIOConfigModel(BaseSettingsModel): - override_global_config: bool = Field( + override_global_config: bool = SettingsField( False, title="Override global OCIO config" ) - filepath: list[str] = Field( + filepath: list[str] = SettingsField( default_factory=list, title="Config path" ) class ImageIOFileRuleModel(BaseSettingsModel): - name: str = Field("", title="Rule name") - pattern: str = Field("", title="Regex pattern") - colorspace: str = Field("", title="Colorspace name") - ext: str = Field("", title="File extension") + name: str = SettingsField("", title="Rule name") + pattern: str = SettingsField("", title="Regex pattern") + colorspace: str = SettingsField("", title="Colorspace name") + ext: str = SettingsField("", title="File extension") class ImageIOFileRulesModel(BaseSettingsModel): - activate_host_rules: bool = Field(False) - rules: list[ImageIOFileRuleModel] = Field( + activate_host_rules: bool = SettingsField(False) + rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, title="Rules" ) @@ -162,17 +163,17 @@ class ImageIOSettings(BaseSettingsModel): now: nuke/imageio/viewer/viewerProcess future: nuke/imageio/viewer """ - activate_host_color_management: bool = Field( + activate_host_color_management: bool = SettingsField( True, title="Enable Color Management") - ocio_config: ImageIOConfigModel = Field( + ocio_config: ImageIOConfigModel = SettingsField( default_factory=ImageIOConfigModel, title="OCIO config" ) - file_rules: ImageIOFileRulesModel = Field( + file_rules: ImageIOFileRulesModel = SettingsField( default_factory=ImageIOFileRulesModel, title="File Rules" ) - viewer: ViewProcessModel = Field( + viewer: ViewProcessModel = SettingsField( default_factory=ViewProcessModel, title="Viewer", description="""Viewer profile is used during @@ -185,19 +186,19 @@ class ImageIOSettings(BaseSettingsModel): now: nuke/imageio/baking/viewerProcess future: nuke/imageio/baking """ - baking: ViewProcessModel = Field( + baking: ViewProcessModel = SettingsField( default_factory=ViewProcessModel, title="Baking", description="""Baking profile is used during publishing baked colorspace data at knob viewerProcess""" ) - workfile: WorkfileColorspaceSettings = Field( + workfile: WorkfileColorspaceSettings = SettingsField( default_factory=WorkfileColorspaceSettings, title="Workfile" ) - nodes: NodesSetting = Field( + nodes: NodesSetting = SettingsField( default_factory=NodesSetting, title="Nodes" ) @@ -205,7 +206,7 @@ class ImageIOSettings(BaseSettingsModel): - [ ] no need for `inputs` middle part. It can stay directly on `regex_inputs` """ - regex_inputs: RegexInputsModel = Field( + regex_inputs: RegexInputsModel = SettingsField( default_factory=RegexInputsModel, title="Assign colorspace to read nodes via rules" ) diff --git a/server_addon/nuke/server/settings/loader_plugins.py b/server_addon/nuke/server/settings/loader_plugins.py index 51e2c2149b..a5c3315fd4 100644 --- a/server_addon/nuke/server/settings/loader_plugins.py +++ b/server_addon/nuke/server/settings/loader_plugins.py @@ -1,54 +1,53 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class LoadImageModel(BaseSettingsModel): - enabled: bool = Field( + enabled: bool = SettingsField( title="Enabled" ) - representations_include: list[str] = Field( + representations_include: list[str] = SettingsField( default_factory=list, title="Include representations" ) - node_name_template: str = Field( + node_name_template: str = SettingsField( title="Read node name template" ) class LoadClipOptionsModel(BaseSettingsModel): - start_at_workfile: bool = Field( + start_at_workfile: bool = SettingsField( title="Start at workfile's start frame" ) - add_retime: bool = Field( + add_retime: bool = SettingsField( title="Add retime" ) class LoadClipModel(BaseSettingsModel): - enabled: bool = Field( + enabled: bool = SettingsField( title="Enabled" ) - representations_include: list[str] = Field( + representations_include: list[str] = SettingsField( default_factory=list, title="Include representations" ) - node_name_template: str = Field( + node_name_template: str = SettingsField( title="Read node name template" ) - options_defaults: LoadClipOptionsModel = Field( + options_defaults: LoadClipOptionsModel = SettingsField( default_factory=LoadClipOptionsModel, title="Loader option defaults" ) class LoaderPuginsModel(BaseSettingsModel): - LoadImage: LoadImageModel = Field( + LoadImage: LoadImageModel = SettingsField( default_factory=LoadImageModel, title="Load Image" ) - LoadClip: LoadClipModel = Field( + LoadClip: LoadClipModel = SettingsField( default_factory=LoadClipModel, title="Load Clip" ) diff --git a/server_addon/nuke/server/settings/main.py b/server_addon/nuke/server/settings/main.py index b6729e7c2f..2b269f1fce 100644 --- a/server_addon/nuke/server/settings/main.py +++ b/server_addon/nuke/server/settings/main.py @@ -1,7 +1,6 @@ -from pydantic import validator, Field - from ayon_server.settings import ( BaseSettingsModel, + SettingsField, ensure_unique_names ) @@ -49,50 +48,50 @@ from .templated_workfile_build import ( class NukeSettings(BaseSettingsModel): """Nuke addon settings.""" - general: GeneralSettings = Field( + general: GeneralSettings = SettingsField( default_factory=GeneralSettings, title="General", ) - imageio: ImageIOSettings = Field( + imageio: ImageIOSettings = SettingsField( default_factory=ImageIOSettings, title="Color Management (imageio)", ) - dirmap: DirmapSettings = Field( + dirmap: DirmapSettings = SettingsField( default_factory=DirmapSettings, title="Nuke Directory Mapping", ) - scriptsmenu: ScriptsmenuSettings = Field( + scriptsmenu: ScriptsmenuSettings = SettingsField( default_factory=ScriptsmenuSettings, title="Scripts Menu Definition", ) - gizmo: list[GizmoItem] = Field( + gizmo: list[GizmoItem] = SettingsField( default_factory=list, title="Gizmo Menu") - create: CreatorPluginsSettings = Field( + create: CreatorPluginsSettings = SettingsField( default_factory=CreatorPluginsSettings, title="Creator Plugins", ) - publish: PublishPuginsModel = Field( + publish: PublishPuginsModel = SettingsField( default_factory=PublishPuginsModel, title="Publish Plugins", ) - load: LoaderPuginsModel = Field( + load: LoaderPuginsModel = SettingsField( default_factory=LoaderPuginsModel, title="Loader Plugins", ) - workfile_builder: WorkfileBuilderModel = Field( + workfile_builder: WorkfileBuilderModel = SettingsField( default_factory=WorkfileBuilderModel, title="Workfile Builder", ) - templated_workfile_build: TemplatedWorkfileBuildModel = Field( + templated_workfile_build: TemplatedWorkfileBuildModel = SettingsField( title="Templated Workfile Build", default_factory=TemplatedWorkfileBuildModel ) diff --git a/server_addon/nuke/server/settings/publish_plugins.py b/server_addon/nuke/server/settings/publish_plugins.py index 84457d2484..02ee9b3bab 100644 --- a/server_addon/nuke/server/settings/publish_plugins.py +++ b/server_addon/nuke/server/settings/publish_plugins.py @@ -1,6 +1,7 @@ -from pydantic import validator, Field +from pydantic import validator from ayon_server.settings import ( BaseSettingsModel, + SettingsField, ensure_unique_names, task_types_enum ) @@ -28,18 +29,18 @@ def nuke_product_types_enum(): class NodeModel(BaseSettingsModel): - name: str = Field( + name: str = SettingsField( title="Node name" ) - nodeclass: str = Field( + nodeclass: str = SettingsField( "", title="Node class" ) - dependent: str = Field( + dependent: str = SettingsField( "", title="Incoming dependency" ) - knobs: list[KnobModel] = Field( + knobs: list[KnobModel] = SettingsField( default_factory=list, title="Knobs", ) @@ -52,7 +53,7 @@ class NodeModel(BaseSettingsModel): class CollectInstanceDataModel(BaseSettingsModel): - sync_workfile_version_on_product_types: list[str] = Field( + sync_workfile_version_on_product_types: list[str] = SettingsField( default_factory=list, enum_resolver=nuke_product_types_enum, title="Sync workfile versions for familes" @@ -60,14 +61,14 @@ class CollectInstanceDataModel(BaseSettingsModel): class OptionalPluginModel(BaseSettingsModel): - enabled: bool = Field(True) - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") + enabled: bool = SettingsField(True) + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") class ValidateKnobsModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - knobs: str = Field( + enabled: bool = SettingsField(title="Enabled") + knobs: str = SettingsField( "{}", title="Knobs", widget="textarea", @@ -79,31 +80,31 @@ class ValidateKnobsModel(BaseSettingsModel): class ExtractReviewDataModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") + enabled: bool = SettingsField(title="Enabled") class ExtractReviewDataLutModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") + enabled: bool = SettingsField(title="Enabled") class BakingStreamFilterModel(BaseSettingsModel): - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - product_types: list[str] = Field( + product_types: list[str] = SettingsField( default_factory=list, enum_resolver=nuke_render_publish_types_enum, title="Sync workfile versions for familes" ) - product_names: list[str] = Field( + product_names: list[str] = SettingsField( default_factory=list, title="Product names") class ReformatNodesRepositionNodes(BaseSettingsModel): - node_class: str = Field(title="Node class") - knobs: list[KnobModel] = Field( + node_class: str = SettingsField(title="Node class") + knobs: list[KnobModel] = SettingsField( default_factory=list, title="Node knobs") @@ -115,41 +116,41 @@ class ReformatNodesConfigModel(BaseSettingsModel): Order of reformat nodes is important. First reformat node will be applied first and last reformat node will be applied last. """ - enabled: bool = Field(False) - reposition_nodes: list[ReformatNodesRepositionNodes] = Field( + enabled: bool = SettingsField(False) + reposition_nodes: list[ReformatNodesRepositionNodes] = SettingsField( default_factory=list, title="Reposition knobs" ) class IntermediateOutputModel(BaseSettingsModel): - name: str = Field(title="Output name") - filter: BakingStreamFilterModel = Field( + name: str = SettingsField(title="Output name") + filter: BakingStreamFilterModel = SettingsField( title="Filter", default_factory=BakingStreamFilterModel) - read_raw: bool = Field( + read_raw: bool = SettingsField( False, title="Read raw switch" ) - viewer_process_override: str = Field( + viewer_process_override: str = SettingsField( "", title="Viewer process override" ) - bake_viewer_process: bool = Field( + bake_viewer_process: bool = SettingsField( True, title="Bake viewer process" ) - bake_viewer_input_process: bool = Field( + bake_viewer_input_process: bool = SettingsField( True, title="Bake viewer input process node (LUT)" ) - reformat_nodes_config: ReformatNodesConfigModel = Field( + reformat_nodes_config: ReformatNodesConfigModel = SettingsField( default_factory=ReformatNodesConfigModel, title="Reformat Nodes") - extension: str = Field( + extension: str = SettingsField( "mov", title="File extension" ) - add_custom_tags: list[str] = Field( + add_custom_tags: list[str] = SettingsField( title="Custom tags", default_factory=list) @@ -157,123 +158,125 @@ class ExtractReviewDataMovModel(BaseSettingsModel): """[deprecated] use Extract Review Data Baking Streams instead. """ - enabled: bool = Field(title="Enabled") - viewer_lut_raw: bool = Field(title="Viewer lut raw") - outputs: list[IntermediateOutputModel] = Field( + enabled: bool = SettingsField(title="Enabled") + viewer_lut_raw: bool = SettingsField(title="Viewer lut raw") + outputs: list[IntermediateOutputModel] = SettingsField( default_factory=list, title="Baking streams" ) class ExtractReviewIntermediatesModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - viewer_lut_raw: bool = Field(title="Viewer lut raw") - outputs: list[IntermediateOutputModel] = Field( + enabled: bool = SettingsField(title="Enabled") + viewer_lut_raw: bool = SettingsField(title="Viewer lut raw") + outputs: list[IntermediateOutputModel] = SettingsField( default_factory=list, title="Baking streams" ) class FSubmissionNoteModel(BaseSettingsModel): - enabled: bool = Field(title="enabled") - template: str = Field(title="Template") + enabled: bool = SettingsField(title="enabled") + template: str = SettingsField(title="Template") class FSubmistingForModel(BaseSettingsModel): - enabled: bool = Field(title="enabled") - template: str = Field(title="Template") + enabled: bool = SettingsField(title="enabled") + template: str = SettingsField(title="Template") class FVFXScopeOfWorkModel(BaseSettingsModel): - enabled: bool = Field(title="enabled") - template: str = Field(title="Template") + enabled: bool = SettingsField(title="enabled") + template: str = SettingsField(title="Template") class ExctractSlateFrameParamModel(BaseSettingsModel): - f_submission_note: FSubmissionNoteModel = Field( + f_submission_note: FSubmissionNoteModel = SettingsField( title="f_submission_note", default_factory=FSubmissionNoteModel ) - f_submitting_for: FSubmistingForModel = Field( + f_submitting_for: FSubmistingForModel = SettingsField( title="f_submitting_for", default_factory=FSubmistingForModel ) - f_vfx_scope_of_work: FVFXScopeOfWorkModel = Field( + f_vfx_scope_of_work: FVFXScopeOfWorkModel = SettingsField( title="f_vfx_scope_of_work", default_factory=FVFXScopeOfWorkModel ) class ExtractSlateFrameModel(BaseSettingsModel): - viewer_lut_raw: bool = Field(title="Viewer lut raw") - key_value_mapping: ExctractSlateFrameParamModel = Field( + viewer_lut_raw: bool = SettingsField(title="Viewer lut raw") + key_value_mapping: ExctractSlateFrameParamModel = SettingsField( title="Key value mapping", default_factory=ExctractSlateFrameParamModel ) class IncrementScriptVersionModel(BaseSettingsModel): - enabled: bool = Field(title="Enabled") - optional: bool = Field(title="Optional") - active: bool = Field(title="Active") + enabled: bool = SettingsField(title="Enabled") + optional: bool = SettingsField(title="Optional") + active: bool = SettingsField(title="Active") class PublishPuginsModel(BaseSettingsModel): - CollectInstanceData: CollectInstanceDataModel = Field( + CollectInstanceData: CollectInstanceDataModel = SettingsField( title="Collect Instance Version", default_factory=CollectInstanceDataModel, section="Collectors" ) - ValidateCorrectAssetContext: OptionalPluginModel = Field( + ValidateCorrectAssetContext: OptionalPluginModel = SettingsField( title="Validate Correct Folder Name", default_factory=OptionalPluginModel, section="Validators" ) - ValidateContainers: OptionalPluginModel = Field( + ValidateContainers: OptionalPluginModel = SettingsField( title="Validate Containers", default_factory=OptionalPluginModel ) - ValidateKnobs: ValidateKnobsModel = Field( + ValidateKnobs: ValidateKnobsModel = SettingsField( title="Validate Knobs", default_factory=ValidateKnobsModel ) - ValidateOutputResolution: OptionalPluginModel = Field( + ValidateOutputResolution: OptionalPluginModel = SettingsField( title="Validate Output Resolution", default_factory=OptionalPluginModel ) - ValidateGizmo: OptionalPluginModel = Field( + ValidateGizmo: OptionalPluginModel = SettingsField( title="Validate Gizmo", default_factory=OptionalPluginModel ) - ValidateBackdrop: OptionalPluginModel = Field( + ValidateBackdrop: OptionalPluginModel = SettingsField( title="Validate Backdrop", default_factory=OptionalPluginModel ) - ValidateScriptAttributes: OptionalPluginModel = Field( + ValidateScriptAttributes: OptionalPluginModel = SettingsField( title="Validate workfile attributes", default_factory=OptionalPluginModel ) - ExtractReviewData: ExtractReviewDataModel = Field( + ExtractReviewData: ExtractReviewDataModel = SettingsField( title="Extract Review Data", default_factory=ExtractReviewDataModel ) - ExtractReviewDataLut: ExtractReviewDataLutModel = Field( + ExtractReviewDataLut: ExtractReviewDataLutModel = SettingsField( title="Extract Review Data Lut", default_factory=ExtractReviewDataLutModel ) - ExtractReviewDataMov: ExtractReviewDataMovModel = Field( + ExtractReviewDataMov: ExtractReviewDataMovModel = SettingsField( title="Extract Review Data Mov", default_factory=ExtractReviewDataMovModel ) - ExtractReviewIntermediates: ExtractReviewIntermediatesModel = Field( - title="Extract Review Intermediates", - default_factory=ExtractReviewIntermediatesModel + ExtractReviewIntermediates: ExtractReviewIntermediatesModel = ( + SettingsField( + title="Extract Review Intermediates", + default_factory=ExtractReviewIntermediatesModel + ) ) - ExtractSlateFrame: ExtractSlateFrameModel = Field( + ExtractSlateFrame: ExtractSlateFrameModel = SettingsField( title="Extract Slate Frame", default_factory=ExtractSlateFrameModel ) - IncrementScriptVersion: IncrementScriptVersionModel = Field( + IncrementScriptVersion: IncrementScriptVersionModel = SettingsField( title="Increment Workfile Version", default_factory=IncrementScriptVersionModel, section="Integrators" diff --git a/server_addon/nuke/server/settings/scriptsmenu.py b/server_addon/nuke/server/settings/scriptsmenu.py index 3dd6765920..7ffd6841d5 100644 --- a/server_addon/nuke/server/settings/scriptsmenu.py +++ b/server_addon/nuke/server/settings/scriptsmenu.py @@ -1,24 +1,23 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class ScriptsmenuSubmodel(BaseSettingsModel): """Item Definition""" _isGroup = True - type: str = Field(title="Type") - command: str = Field(title="Command") - sourcetype: str = Field(title="Source Type") - title: str = Field(title="Title") - tooltip: str = Field(title="Tooltip") + type: str = SettingsField(title="Type") + command: str = SettingsField(title="Command") + sourcetype: str = SettingsField(title="Source Type") + title: str = SettingsField(title="Title") + tooltip: str = SettingsField(title="Tooltip") class ScriptsmenuSettings(BaseSettingsModel): """Nuke script menu project settings.""" _isGroup = True - name: str = Field(title="Menu Name") - definition: list[ScriptsmenuSubmodel] = Field( + name: str = SettingsField(title="Menu Name") + definition: list[ScriptsmenuSubmodel] = SettingsField( default_factory=list, title="Definition", description="Scriptmenu Items Definition" diff --git a/server_addon/nuke/server/settings/templated_workfile_build.py b/server_addon/nuke/server/settings/templated_workfile_build.py index 0899be841e..12ebedf570 100644 --- a/server_addon/nuke/server/settings/templated_workfile_build.py +++ b/server_addon/nuke/server/settings/templated_workfile_build.py @@ -1,27 +1,27 @@ -from pydantic import Field from ayon_server.settings import ( BaseSettingsModel, + SettingsField, task_types_enum, ) class TemplatedWorkfileProfileModel(BaseSettingsModel): - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - task_names: list[str] = Field( + task_names: list[str] = SettingsField( default_factory=list, title="Task names" ) - path: str = Field( + path: str = SettingsField( title="Path to template" ) - keep_placeholder: bool = Field( + keep_placeholder: bool = SettingsField( False, title="Keep placeholders") - create_first_version: bool = Field( + create_first_version: bool = SettingsField( True, title="Create first version" ) @@ -29,6 +29,6 @@ class TemplatedWorkfileProfileModel(BaseSettingsModel): class TemplatedWorkfileBuildModel(BaseSettingsModel): """Settings for templated workfile builder.""" - profiles: list[TemplatedWorkfileProfileModel] = Field( + profiles: list[TemplatedWorkfileProfileModel] = SettingsField( default_factory=list ) diff --git a/server_addon/nuke/server/settings/workfile_builder.py b/server_addon/nuke/server/settings/workfile_builder.py index 3ae3b08788..97961655f3 100644 --- a/server_addon/nuke/server/settings/workfile_builder.py +++ b/server_addon/nuke/server/settings/workfile_builder.py @@ -1,57 +1,57 @@ -from pydantic import Field from ayon_server.settings import ( BaseSettingsModel, + SettingsField, task_types_enum, MultiplatformPathModel, ) class CustomTemplateModel(BaseSettingsModel): - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - path: MultiplatformPathModel = Field( + path: MultiplatformPathModel = SettingsField( default_factory=MultiplatformPathModel, title="Gizmo Directory Path" ) class BuilderProfileItemModel(BaseSettingsModel): - product_name_filters: list[str] = Field( + product_name_filters: list[str] = SettingsField( default_factory=list, title="Product name" ) - product_types: list[str] = Field( + product_types: list[str] = SettingsField( default_factory=list, title="Product types" ) - repre_names: list[str] = Field( + repre_names: list[str] = SettingsField( default_factory=list, title="Representations" ) - loaders: list[str] = Field( + loaders: list[str] = SettingsField( default_factory=list, title="Loader plugins" ) class BuilderProfileModel(BaseSettingsModel): - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - tasks: list[str] = Field( + tasks: list[str] = SettingsField( default_factory=list, title="Task names" ) - current_context: list[BuilderProfileItemModel] = Field( + current_context: list[BuilderProfileItemModel] = SettingsField( default_factory=list, title="Current context" ) - linked_assets: list[BuilderProfileItemModel] = Field( + linked_assets: list[BuilderProfileItemModel] = SettingsField( default_factory=list, title="Linked assets/shots" ) @@ -60,17 +60,17 @@ class BuilderProfileModel(BaseSettingsModel): class WorkfileBuilderModel(BaseSettingsModel): """[deprecated] use Template Workfile Build Settings instead. """ - create_first_version: bool = Field( + create_first_version: bool = SettingsField( title="Create first workfile") - custom_templates: list[CustomTemplateModel] = Field( + custom_templates: list[CustomTemplateModel] = SettingsField( default_factory=list, title="Custom templates" ) - builder_on_start: bool = Field( + builder_on_start: bool = SettingsField( default=False, title="Run Builder at first workfile" ) - profiles: list[BuilderProfileModel] = Field( + profiles: list[BuilderProfileModel] = SettingsField( default_factory=list, title="Builder profiles" ) diff --git a/server_addon/photoshop/server/settings/creator_plugins.py b/server_addon/photoshop/server/settings/creator_plugins.py index 2fe63a7e3a..8acc213866 100644 --- a/server_addon/photoshop/server/settings/creator_plugins.py +++ b/server_addon/photoshop/server/settings/creator_plugins.py @@ -1,51 +1,49 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class CreateImagePluginModel(BaseSettingsModel): - enabled: bool = Field(True, title="Enabled") - active_on_create: bool = Field(True, title="Active by default") - mark_for_review: bool = Field(False, title="Review by default") - default_variants: list[str] = Field( + enabled: bool = SettingsField(True, title="Enabled") + active_on_create: bool = SettingsField(True, title="Active by default") + mark_for_review: bool = SettingsField(False, title="Review by default") + default_variants: list[str] = SettingsField( default_factory=list, title="Default Variants" ) class AutoImageCreatorPluginModel(BaseSettingsModel): - enabled: bool = Field(False, title="Enabled") - active_on_create: bool = Field(True, title="Active by default") - mark_for_review: bool = Field(False, title="Review by default") - default_variant: str = Field("", title="Default Variants") + enabled: bool = SettingsField(False, title="Enabled") + active_on_create: bool = SettingsField(True, title="Active by default") + mark_for_review: bool = SettingsField(False, title="Review by default") + default_variant: str = SettingsField("", title="Default Variants") class CreateReviewPlugin(BaseSettingsModel): - enabled: bool = Field(True, title="Enabled") - active_on_create: bool = Field(True, title="Active by default") - default_variant: str = Field("", title="Default Variants") + enabled: bool = SettingsField(True, title="Enabled") + active_on_create: bool = SettingsField(True, title="Active by default") + default_variant: str = SettingsField("", title="Default Variants") class CreateWorkfilelugin(BaseSettingsModel): - enabled: bool = Field(True, title="Enabled") - active_on_create: bool = Field(True, title="Active by default") - default_variant: str = Field("", title="Default Variants") + enabled: bool = SettingsField(True, title="Enabled") + active_on_create: bool = SettingsField(True, title="Active by default") + default_variant: str = SettingsField("", title="Default Variants") class PhotoshopCreatorPlugins(BaseSettingsModel): - ImageCreator: CreateImagePluginModel = Field( + ImageCreator: CreateImagePluginModel = SettingsField( title="Create Image", default_factory=CreateImagePluginModel, ) - AutoImageCreator: AutoImageCreatorPluginModel = Field( + AutoImageCreator: AutoImageCreatorPluginModel = SettingsField( title="Create Flatten Image", default_factory=AutoImageCreatorPluginModel, ) - ReviewCreator: CreateReviewPlugin = Field( + ReviewCreator: CreateReviewPlugin = SettingsField( title="Create Review", default_factory=CreateReviewPlugin, ) - WorkfileCreator: CreateWorkfilelugin = Field( + WorkfileCreator: CreateWorkfilelugin = SettingsField( title="Create Workfile", default_factory=CreateWorkfilelugin, ) diff --git a/server_addon/photoshop/server/settings/imageio.py b/server_addon/photoshop/server/settings/imageio.py index 56b7f2fa32..9178497c6c 100644 --- a/server_addon/photoshop/server/settings/imageio.py +++ b/server_addon/photoshop/server/settings/imageio.py @@ -1,29 +1,29 @@ -from pydantic import Field, validator -from ayon_server.settings import BaseSettingsModel +from pydantic import validator +from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.settings.validators import ensure_unique_names class ImageIOConfigModel(BaseSettingsModel): - override_global_config: bool = Field( + override_global_config: bool = SettingsField( False, title="Override global OCIO config" ) - filepath: list[str] = Field( + filepath: list[str] = SettingsField( default_factory=list, title="Config path" ) class ImageIOFileRuleModel(BaseSettingsModel): - name: str = Field("", title="Rule name") - pattern: str = Field("", title="Regex pattern") - colorspace: str = Field("", title="Colorspace name") - ext: str = Field("", title="File extension") + name: str = SettingsField("", title="Rule name") + pattern: str = SettingsField("", title="Regex pattern") + colorspace: str = SettingsField("", title="Colorspace name") + ext: str = SettingsField("", title="File extension") class ImageIOFileRulesModel(BaseSettingsModel): - activate_host_rules: bool = Field(False) - rules: list[ImageIOFileRuleModel] = Field( + activate_host_rules: bool = SettingsField(False) + rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, title="Rules" ) @@ -35,30 +35,30 @@ class ImageIOFileRulesModel(BaseSettingsModel): class ImageIORemappingRulesModel(BaseSettingsModel): - host_native_name: str = Field( + host_native_name: str = SettingsField( title="Application native colorspace name" ) - ocio_name: str = Field(title="OCIO colorspace name") + ocio_name: str = SettingsField(title="OCIO colorspace name") class ImageIORemappingModel(BaseSettingsModel): - rules: list[ImageIORemappingRulesModel] = Field( + rules: list[ImageIORemappingRulesModel] = SettingsField( default_factory=list) class PhotoshopImageIOModel(BaseSettingsModel): - activate_host_color_management: bool = Field( + activate_host_color_management: bool = SettingsField( True, title="Enable Color Management" ) - remapping: ImageIORemappingModel = Field( + remapping: ImageIORemappingModel = SettingsField( title="Remapping colorspace names", default_factory=ImageIORemappingModel ) - ocio_config: ImageIOConfigModel = Field( + ocio_config: ImageIOConfigModel = SettingsField( default_factory=ImageIOConfigModel, title="OCIO config" ) - file_rules: ImageIOFileRulesModel = Field( + file_rules: ImageIOFileRulesModel = SettingsField( default_factory=ImageIOFileRulesModel, title="File Rules" ) diff --git a/server_addon/photoshop/server/settings/main.py b/server_addon/photoshop/server/settings/main.py index ae7705b3db..b6474d6d29 100644 --- a/server_addon/photoshop/server/settings/main.py +++ b/server_addon/photoshop/server/settings/main.py @@ -1,5 +1,4 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField from .imageio import PhotoshopImageIOModel from .creator_plugins import PhotoshopCreatorPlugins, DEFAULT_CREATE_SETTINGS @@ -10,22 +9,22 @@ from .workfile_builder import WorkfileBuilderPlugin class PhotoshopSettings(BaseSettingsModel): """Photoshop Project Settings.""" - imageio: PhotoshopImageIOModel = Field( + imageio: PhotoshopImageIOModel = SettingsField( default_factory=PhotoshopImageIOModel, title="OCIO config" ) - create: PhotoshopCreatorPlugins = Field( + create: PhotoshopCreatorPlugins = SettingsField( default_factory=PhotoshopCreatorPlugins, title="Creator plugins" ) - publish: PhotoshopPublishPlugins = Field( + publish: PhotoshopPublishPlugins = SettingsField( default_factory=PhotoshopPublishPlugins, title="Publish plugins" ) - workfile_builder: WorkfileBuilderPlugin = Field( + workfile_builder: WorkfileBuilderPlugin = SettingsField( default_factory=WorkfileBuilderPlugin, title="Workfile Builder" ) diff --git a/server_addon/photoshop/server/settings/publish_plugins.py b/server_addon/photoshop/server/settings/publish_plugins.py index 21e7d670f0..c4a392d490 100644 --- a/server_addon/photoshop/server/settings/publish_plugins.py +++ b/server_addon/photoshop/server/settings/publish_plugins.py @@ -1,6 +1,4 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField create_flatten_image_enum = [ @@ -22,30 +20,30 @@ color_code_enum = [ class ColorCodeMappings(BaseSettingsModel): - color_code: list[str] = Field( + color_code: list[str] = SettingsField( title="Color codes for layers", default_factory=list, enum_resolver=lambda: color_code_enum, ) - layer_name_regex: list[str] = Field( + layer_name_regex: list[str] = SettingsField( default_factory=list, title="Layer name regex" ) - product_type: str = Field( + product_type: str = SettingsField( "", title="Resulting product type" ) - product_name_template: str = Field( + product_name_template: str = SettingsField( "", title="Product name template" ) class ExtractedOptions(BaseSettingsModel): - tags: list[str] = Field( + tags: list[str] = SettingsField( title="Tags", default_factory=list ) @@ -57,19 +55,19 @@ class CollectColorCodedInstancesPlugin(BaseSettingsModel): instances. (Applicable only for remote publishing!)""" - enabled: bool = Field(True, title="Enabled") - create_flatten_image: str = Field( + enabled: bool = SettingsField(True, title="Enabled") + create_flatten_image: str = SettingsField( "", title="Create flatten image", enum_resolver=lambda: create_flatten_image_enum, ) - flatten_product_type_template: str = Field( + flatten_product_type_template: str = SettingsField( "", title="Subset template for flatten image" ) - color_code_mapping: list[ColorCodeMappings] = Field( + color_code_mapping: list[ColorCodeMappings] = SettingsField( title="Color code mappings", default_factory=ColorCodeMappings, ) @@ -77,30 +75,30 @@ class CollectColorCodedInstancesPlugin(BaseSettingsModel): class CollectReviewPlugin(BaseSettingsModel): """Should review product be created""" - enabled: bool = Field(True, title="Enabled") + enabled: bool = SettingsField(True, title="Enabled") class CollectVersionPlugin(BaseSettingsModel): """Synchronize version for image and review instances by workfile version""" # noqa - enabled: bool = Field(True, title="Enabled") + enabled: bool = SettingsField(True, title="Enabled") class ValidateContainersPlugin(BaseSettingsModel): """Check that workfile contains latest version of loaded items""" # noqa _isGroup = True enabled: bool = True - optional: bool = Field(False, title="Optional") - active: bool = Field(True, title="Active") + optional: bool = SettingsField(False, title="Optional") + active: bool = SettingsField(True, title="Active") class ValidateNamingPlugin(BaseSettingsModel): """Validate naming of products and layers""" # noqa - invalid_chars: str = Field( + invalid_chars: str = SettingsField( '', title="Regex pattern of invalid characters" ) - replace_char: str = Field( + replace_char: str = SettingsField( '', title="Replacement character" ) @@ -108,19 +106,19 @@ class ValidateNamingPlugin(BaseSettingsModel): class ExtractImagePlugin(BaseSettingsModel): """Currently only jpg and png are supported""" - formats: list[str] = Field( + formats: list[str] = SettingsField( title="Extract Formats", default_factory=list, ) class ExtractReviewPlugin(BaseSettingsModel): - make_image_sequence: bool = Field( + make_image_sequence: bool = SettingsField( False, title="Make an image sequence instead of flatten image" ) - max_downscale_size: int = Field( + max_downscale_size: int = SettingsField( 8192, title="Maximum size of sources for review", description="FFMpeg can only handle limited resolution for creation of review and/or thumbnail", # noqa @@ -128,48 +126,50 @@ class ExtractReviewPlugin(BaseSettingsModel): le=16384, # less or equal ) - jpg_options: ExtractedOptions = Field( + jpg_options: ExtractedOptions = SettingsField( title="Extracted jpg Options", default_factory=ExtractedOptions ) - mov_options: ExtractedOptions = Field( + mov_options: ExtractedOptions = SettingsField( title="Extracted mov Options", default_factory=ExtractedOptions ) class PhotoshopPublishPlugins(BaseSettingsModel): - CollectColorCodedInstances: CollectColorCodedInstancesPlugin = Field( - title="Collect Color Coded Instances", - default_factory=CollectColorCodedInstancesPlugin, + CollectColorCodedInstances: CollectColorCodedInstancesPlugin = ( + SettingsField( + title="Collect Color Coded Instances", + default_factory=CollectColorCodedInstancesPlugin, + ) ) - CollectReview: CollectReviewPlugin = Field( + CollectReview: CollectReviewPlugin = SettingsField( title="Collect Review", default_factory=CollectReviewPlugin, ) - CollectVersion: CollectVersionPlugin = Field( + CollectVersion: CollectVersionPlugin = SettingsField( title="Collect Version", default_factory=CollectVersionPlugin, ) - ValidateContainers: ValidateContainersPlugin = Field( + ValidateContainers: ValidateContainersPlugin = SettingsField( title="Validate Containers", default_factory=ValidateContainersPlugin, ) - ValidateNaming: ValidateNamingPlugin = Field( + ValidateNaming: ValidateNamingPlugin = SettingsField( title="Validate naming of products and layers", default_factory=ValidateNamingPlugin, ) - ExtractImage: ExtractImagePlugin = Field( + ExtractImage: ExtractImagePlugin = SettingsField( title="Extract Image", default_factory=ExtractImagePlugin, ) - ExtractReview: ExtractReviewPlugin = Field( + ExtractReview: ExtractReviewPlugin = SettingsField( title="Extract Review", default_factory=ExtractReviewPlugin, ) diff --git a/server_addon/photoshop/server/settings/workfile_builder.py b/server_addon/photoshop/server/settings/workfile_builder.py index 68db05270d..4b00b99272 100644 --- a/server_addon/photoshop/server/settings/workfile_builder.py +++ b/server_addon/photoshop/server/settings/workfile_builder.py @@ -1,16 +1,18 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel, MultiplatformPathModel +from ayon_server.settings import ( + BaseSettingsModel, + SettingsField, + MultiplatformPathModel, +) class CustomBuilderTemplate(BaseSettingsModel): _layout = "expanded" - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, title="Task types", ) - path: MultiplatformPathModel = Field( + path: MultiplatformPathModel = SettingsField( default_factory=MultiplatformPathModel, title="Template path" ) @@ -18,12 +20,12 @@ class CustomBuilderTemplate(BaseSettingsModel): class WorkfileBuilderPlugin(BaseSettingsModel): _title = "Workfile Builder" - create_first_version: bool = Field( + create_first_version: bool = SettingsField( False, title="Create first workfile" ) - custom_templates: list[CustomBuilderTemplate] = Field( + custom_templates: list[CustomBuilderTemplate] = SettingsField( default_factory=CustomBuilderTemplate, title="Template profiles" ) diff --git a/server_addon/resolve/server/imageio.py b/server_addon/resolve/server/imageio.py index c2bfcd40d0..9540f5d1d9 100644 --- a/server_addon/resolve/server/imageio.py +++ b/server_addon/resolve/server/imageio.py @@ -1,29 +1,29 @@ -from pydantic import Field, validator -from ayon_server.settings import BaseSettingsModel +from pydantic import validator +from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.settings.validators import ensure_unique_names class ImageIOConfigModel(BaseSettingsModel): - override_global_config: bool = Field( + override_global_config: bool = SettingsField( False, title="Override global OCIO config" ) - filepath: list[str] = Field( + filepath: list[str] = SettingsField( default_factory=list, title="Config path" ) class ImageIOFileRuleModel(BaseSettingsModel): - name: str = Field("", title="Rule name") - pattern: str = Field("", title="Regex pattern") - colorspace: str = Field("", title="Colorspace name") - ext: str = Field("", title="File extension") + name: str = SettingsField("", title="Rule name") + pattern: str = SettingsField("", title="Regex pattern") + colorspace: str = SettingsField("", title="Colorspace name") + ext: str = SettingsField("", title="File extension") class ImageIOFileRulesModel(BaseSettingsModel): - activate_host_rules: bool = Field(False) - rules: list[ImageIOFileRuleModel] = Field( + activate_host_rules: bool = SettingsField(False) + rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, title="Rules" ) @@ -35,30 +35,30 @@ class ImageIOFileRulesModel(BaseSettingsModel): class ImageIORemappingRulesModel(BaseSettingsModel): - host_native_name: str = Field( + host_native_name: str = SettingsField( title="Application native colorspace name" ) - ocio_name: str = Field(title="OCIO colorspace name") + ocio_name: str = SettingsField(title="OCIO colorspace name") class ImageIORemappingModel(BaseSettingsModel): - rules: list[ImageIORemappingRulesModel] = Field( + rules: list[ImageIORemappingRulesModel] = SettingsField( default_factory=list) class ResolveImageIOModel(BaseSettingsModel): - activate_host_color_management: bool = Field( + activate_host_color_management: bool = SettingsField( True, title="Enable Color Management" ) - remapping: ImageIORemappingModel = Field( + remapping: ImageIORemappingModel = SettingsField( title="Remapping colorspace names", default_factory=ImageIORemappingModel ) - ocio_config: ImageIOConfigModel = Field( + ocio_config: ImageIOConfigModel = SettingsField( default_factory=ImageIOConfigModel, title="OCIO config" ) - file_rules: ImageIOFileRulesModel = Field( + file_rules: ImageIOFileRulesModel = SettingsField( default_factory=ImageIOFileRulesModel, title="File Rules" ) diff --git a/server_addon/resolve/server/settings.py b/server_addon/resolve/server/settings.py index 326f6bea1e..dcdb2f1b27 100644 --- a/server_addon/resolve/server/settings.py +++ b/server_addon/resolve/server/settings.py @@ -1,91 +1,90 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField from .imageio import ResolveImageIOModel class CreateShotClipModels(BaseSettingsModel): - hierarchy: str = Field( + hierarchy: str = SettingsField( "{folder}/{sequence}", title="Shot parent hierarchy", section="Shot Hierarchy And Rename Settings" ) - clipRename: bool = Field( + clipRename: bool = SettingsField( True, title="Rename clips" ) - clipName: str = Field( + clipName: str = SettingsField( "{track}{sequence}{shot}", title="Clip name template" ) - countFrom: int = Field( + countFrom: int = SettingsField( 10, title="Count sequence from" ) - countSteps: int = Field( + countSteps: int = SettingsField( 10, title="Stepping number" ) - folder: str = Field( + folder: str = SettingsField( "shots", title="{folder}", section="Shot Template Keywords" ) - episode: str = Field( + episode: str = SettingsField( "ep01", title="{episode}" ) - sequence: str = Field( + sequence: str = SettingsField( "sq01", title="{sequence}" ) - track: str = Field( + track: str = SettingsField( "{_track_}", title="{track}" ) - shot: str = Field( + shot: str = SettingsField( "sh###", title="{shot}" ) - vSyncOn: bool = Field( + vSyncOn: bool = SettingsField( False, title="Enable Vertical Sync", section="Vertical Synchronization Of Attributes" ) - workfileFrameStart: int = Field( + workfileFrameStart: int = SettingsField( 1001, title="Workfiles Start Frame", section="Shot Attributes" ) - handleStart: int = Field( + handleStart: int = SettingsField( 10, title="Handle start (head)" ) - handleEnd: int = Field( + handleEnd: int = SettingsField( 10, title="Handle end (tail)" ) class CreatorPuginsModel(BaseSettingsModel): - CreateShotClip: CreateShotClipModels = Field( + CreateShotClip: CreateShotClipModels = SettingsField( default_factory=CreateShotClipModels, title="Create Shot Clip" ) class ResolveSettings(BaseSettingsModel): - launch_openpype_menu_on_start: bool = Field( + launch_openpype_menu_on_start: bool = SettingsField( False, title="Launch OpenPype menu on start of Resolve" ) - imageio: ResolveImageIOModel = Field( + imageio: ResolveImageIOModel = SettingsField( default_factory=ResolveImageIOModel, title="Color Management (ImageIO)" ) - create: CreatorPuginsModel = Field( + create: CreatorPuginsModel = SettingsField( default_factory=CreatorPuginsModel, title="Creator plugins", ) diff --git a/server_addon/royal_render/server/settings.py b/server_addon/royal_render/server/settings.py index 677d7e2671..6e077feb3e 100644 --- a/server_addon/royal_render/server/settings.py +++ b/server_addon/royal_render/server/settings.py @@ -1,5 +1,8 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel, MultiplatformPathModel +from ayon_server.settings import ( + BaseSettingsModel, + SettingsField, + MultiplatformPathModel, +) class CustomPath(MultiplatformPathModel): @@ -8,18 +11,20 @@ class CustomPath(MultiplatformPathModel): class ServerListSubmodel(BaseSettingsModel): _layout = "expanded" - name: str = Field("", title="Name") - value: CustomPath = Field( + name: str = SettingsField("", title="Name") + value: CustomPath = SettingsField( default_factory=CustomPath ) class CollectSequencesFromJobModel(BaseSettingsModel): - review: bool = Field(True, title="Generate reviews from sequences") + review: bool = SettingsField( + True, title="Generate reviews from sequences" + ) class PublishPluginsModel(BaseSettingsModel): - CollectSequencesFromJob: CollectSequencesFromJobModel = Field( + CollectSequencesFromJob: CollectSequencesFromJobModel = SettingsField( default_factory=CollectSequencesFromJobModel, title="Collect Sequences from the Job" ) @@ -31,19 +36,19 @@ class RoyalRenderSettings(BaseSettingsModel): # - both system and project settings contained 'rr_path' # where project settings did choose one of rr_path from system settings # that is not possible in AYON - rr_paths: list[ServerListSubmodel] = Field( + rr_paths: list[ServerListSubmodel] = SettingsField( default_factory=list, title="Royal Render Root Paths", scope=["studio"], ) # This was 'rr_paths' in project settings and should be enum of # 'rr_paths' from system settings, but that's not possible in AYON - selected_rr_paths: list[str] = Field( + selected_rr_paths: list[str] = SettingsField( default_factory=list, title="Selected Royal Render Paths", section="---", ) - publish: PublishPluginsModel = Field( + publish: PublishPluginsModel = SettingsField( default_factory=PublishPluginsModel, title="Publish plugins", ) diff --git a/server_addon/substancepainter/server/settings/imageio.py b/server_addon/substancepainter/server/settings/imageio.py index e301d3d865..ea685047b0 100644 --- a/server_addon/substancepainter/server/settings/imageio.py +++ b/server_addon/substancepainter/server/settings/imageio.py @@ -1,29 +1,29 @@ -from pydantic import Field, validator -from ayon_server.settings import BaseSettingsModel +from pydantic import validator +from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.settings.validators import ensure_unique_names class ImageIOConfigModel(BaseSettingsModel): - override_global_config: bool = Field( + override_global_config: bool = SettingsField( False, title="Override global OCIO config" ) - filepath: list[str] = Field( + filepath: list[str] = SettingsField( default_factory=list, title="Config path" ) class ImageIOFileRuleModel(BaseSettingsModel): - name: str = Field("", title="Rule name") - pattern: str = Field("", title="Regex pattern") - colorspace: str = Field("", title="Colorspace name") - ext: str = Field("", title="File extension") + name: str = SettingsField("", title="Rule name") + pattern: str = SettingsField("", title="Regex pattern") + colorspace: str = SettingsField("", title="Colorspace name") + ext: str = SettingsField("", title="File extension") class ImageIOFileRulesModel(BaseSettingsModel): - activate_host_rules: bool = Field(False) - rules: list[ImageIOFileRuleModel] = Field( + activate_host_rules: bool = SettingsField(False) + rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, title="Rules" ) @@ -35,14 +35,14 @@ class ImageIOFileRulesModel(BaseSettingsModel): class ImageIOSettings(BaseSettingsModel): - activate_host_color_management: bool = Field( + activate_host_color_management: bool = SettingsField( True, title="Enable Color Management" ) - ocio_config: ImageIOConfigModel = Field( + ocio_config: ImageIOConfigModel = SettingsField( default_factory=ImageIOConfigModel, title="OCIO config" ) - file_rules: ImageIOFileRulesModel = Field( + file_rules: ImageIOFileRulesModel = SettingsField( default_factory=ImageIOFileRulesModel, title="File Rules" ) diff --git a/server_addon/substancepainter/server/settings/main.py b/server_addon/substancepainter/server/settings/main.py index f8397c3c08..f80fa9fe1e 100644 --- a/server_addon/substancepainter/server/settings/main.py +++ b/server_addon/substancepainter/server/settings/main.py @@ -1,20 +1,19 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField from .imageio import ImageIOSettings, DEFAULT_IMAGEIO_SETTINGS class ShelvesSettingsModel(BaseSettingsModel): _layout = "compact" - name: str = Field(title="Name") - value: str = Field(title="Path") + name: str = SettingsField(title="Name") + value: str = SettingsField(title="Path") class SubstancePainterSettings(BaseSettingsModel): - imageio: ImageIOSettings = Field( + imageio: ImageIOSettings = SettingsField( default_factory=ImageIOSettings, title="Color Management (ImageIO)" ) - shelves: list[ShelvesSettingsModel] = Field( + shelves: list[ShelvesSettingsModel] = SettingsField( default_factory=list, title="Shelves" ) diff --git a/server_addon/timers_manager/server/settings.py b/server_addon/timers_manager/server/settings.py index a5c5721a57..774940730c 100644 --- a/server_addon/timers_manager/server/settings.py +++ b/server_addon/timers_manager/server/settings.py @@ -1,24 +1,23 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class TimersManagerSettings(BaseSettingsModel): - auto_stop: bool = Field( + auto_stop: bool = SettingsField( True, title="Auto stop timer", scope=["studio"], ) - full_time: int = Field( + full_time: int = SettingsField( 15, title="Max idle time", scope=["studio"], ) - message_time: float = Field( + message_time: float = SettingsField( 0.5, title="When dialog will show", scope=["studio"], ) - disregard_publishing: bool = Field( + disregard_publishing: bool = SettingsField( False, title="Disregard publishing", scope=["studio"], diff --git a/server_addon/traypublisher/server/settings/creator_plugins.py b/server_addon/traypublisher/server/settings/creator_plugins.py index 345cb92e63..bf66d9a088 100644 --- a/server_addon/traypublisher/server/settings/creator_plugins.py +++ b/server_addon/traypublisher/server/settings/creator_plugins.py @@ -1,6 +1,4 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class BatchMovieCreatorPlugin(BaseSettingsModel): @@ -8,24 +6,24 @@ class BatchMovieCreatorPlugin(BaseSettingsModel): asset is parsed from file names ('asset.mov', 'asset_v001.mov', 'my_asset_to_publish.mov')""" - default_variants: list[str] = Field( + default_variants: list[str] = SettingsField( title="Default variants", default_factory=list ) - default_tasks: list[str] = Field( + default_tasks: list[str] = SettingsField( title="Default tasks", default_factory=list ) - extensions: list[str] = Field( + extensions: list[str] = SettingsField( title="Extensions", default_factory=list ) class TrayPublisherCreatePluginsModel(BaseSettingsModel): - BatchMovieCreator: BatchMovieCreatorPlugin = Field( + BatchMovieCreator: BatchMovieCreatorPlugin = SettingsField( title="Batch Movie Creator", default_factory=BatchMovieCreatorPlugin ) diff --git a/server_addon/traypublisher/server/settings/editorial_creators.py b/server_addon/traypublisher/server/settings/editorial_creators.py index ac0ff0afc7..d9f5e302a4 100644 --- a/server_addon/traypublisher/server/settings/editorial_creators.py +++ b/server_addon/traypublisher/server/settings/editorial_creators.py @@ -1,18 +1,20 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel, task_types_enum +from ayon_server.settings import ( + BaseSettingsModel, + SettingsField, + task_types_enum, +) class ClipNameTokenizerItem(BaseSettingsModel): _layout = "expanded" - name: str = Field("", title="Tokenizer name") - regex: str = Field("", title="Tokenizer regex") + name: str = SettingsField("", title="Tokenizer name") + regex: str = SettingsField("", title="Tokenizer regex") class ShotAddTasksItem(BaseSettingsModel): _layout = "expanded" - name: str = Field('', title="Key") - task_type: str = Field( + name: str = SettingsField('', title="Key") + task_type: str = SettingsField( title="Task type", enum_resolver=task_types_enum ) @@ -20,7 +22,7 @@ class ShotAddTasksItem(BaseSettingsModel): class ShotRenameSubmodel(BaseSettingsModel): enabled: bool = True - shot_rename_template: str = Field( + shot_rename_template: str = SettingsField( "", title="Shot rename template" ) @@ -36,16 +38,16 @@ parent_type_enum = [ class TokenToParentConvertorItem(BaseSettingsModel): # TODO - was 'type' must be renamed in code to `parent_type` - parent_type: str = Field( + parent_type: str = SettingsField( "Project", enum_resolver=lambda: parent_type_enum ) - name: str = Field( + name: str = SettingsField( "", title="Parent token name", description="Unique name used in `Parent path template`" ) - value: str = Field( + value: str = SettingsField( "", title="Parent token value", description="Template where any text, Anatomy keys and Tokens could be used" # noqa @@ -54,12 +56,12 @@ class TokenToParentConvertorItem(BaseSettingsModel): class ShotHierarchySubmodel(BaseSettingsModel): enabled: bool = True - parents_path: str = Field( + parents_path: str = SettingsField( "", title="Parents path template", description="Using keys from \"Token to parent convertor\" or tokens directly" # noqa ) - parents: list[TokenToParentConvertorItem] = Field( + parents: list[TokenToParentConvertorItem] = SettingsField( default_factory=TokenToParentConvertorItem, title="Token to parent convertor" ) @@ -73,22 +75,22 @@ output_file_type = [ class ProductTypePresetItem(BaseSettingsModel): - product_type: str = Field("", title="Product type") + product_type: str = SettingsField("", title="Product type") # TODO add placeholder '< Inherited >' - variant: str = Field("", title="Variant") - review: bool = Field(True, title="Review") - output_file_type: str = Field( + variant: str = SettingsField("", title="Variant") + review: bool = SettingsField(True, title="Review") + output_file_type: str = SettingsField( ".mp4", enum_resolver=lambda: output_file_type ) class EditorialSimpleCreatorPlugin(BaseSettingsModel): - default_variants: list[str] = Field( + default_variants: list[str] = SettingsField( default_factory=list, title="Default Variants" ) - clip_name_tokenizer: list[ClipNameTokenizerItem] = Field( + clip_name_tokenizer: list[ClipNameTokenizerItem] = SettingsField( default_factory=ClipNameTokenizerItem, description=( "Using Regex expression to create tokens. \nThose can be used" @@ -96,25 +98,25 @@ class EditorialSimpleCreatorPlugin(BaseSettingsModel): "\n\nTokens should be decorated with \"_\" on each side" ) ) - shot_rename: ShotRenameSubmodel = Field( + shot_rename: ShotRenameSubmodel = SettingsField( title="Shot Rename", default_factory=ShotRenameSubmodel ) - shot_hierarchy: ShotHierarchySubmodel = Field( + shot_hierarchy: ShotHierarchySubmodel = SettingsField( title="Shot Hierarchy", default_factory=ShotHierarchySubmodel ) - shot_add_tasks: list[ShotAddTasksItem] = Field( + shot_add_tasks: list[ShotAddTasksItem] = SettingsField( title="Add tasks to shot", default_factory=ShotAddTasksItem ) - product_type_presets: list[ProductTypePresetItem] = Field( + product_type_presets: list[ProductTypePresetItem] = SettingsField( default_factory=list ) class TraypublisherEditorialCreatorPlugins(BaseSettingsModel): - editorial_simple: EditorialSimpleCreatorPlugin = Field( + editorial_simple: EditorialSimpleCreatorPlugin = SettingsField( title="Editorial simple creator", default_factory=EditorialSimpleCreatorPlugin, ) diff --git a/server_addon/traypublisher/server/settings/imageio.py b/server_addon/traypublisher/server/settings/imageio.py index 3df0d2f2fb..06a18a39ca 100644 --- a/server_addon/traypublisher/server/settings/imageio.py +++ b/server_addon/traypublisher/server/settings/imageio.py @@ -1,29 +1,29 @@ -from pydantic import Field, validator -from ayon_server.settings import BaseSettingsModel +from pydantic import validator +from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.settings.validators import ensure_unique_names class ImageIOConfigModel(BaseSettingsModel): - override_global_config: bool = Field( + override_global_config: bool = SettingsField( False, title="Override global OCIO config" ) - filepath: list[str] = Field( + filepath: list[str] = SettingsField( default_factory=list, title="Config path" ) class ImageIOFileRuleModel(BaseSettingsModel): - name: str = Field("", title="Rule name") - pattern: str = Field("", title="Regex pattern") - colorspace: str = Field("", title="Colorspace name") - ext: str = Field("", title="File extension") + name: str = SettingsField("", title="Rule name") + pattern: str = SettingsField("", title="Regex pattern") + colorspace: str = SettingsField("", title="Colorspace name") + ext: str = SettingsField("", title="File extension") class ImageIOFileRulesModel(BaseSettingsModel): - activate_host_rules: bool = Field(False) - rules: list[ImageIOFileRuleModel] = Field( + activate_host_rules: bool = SettingsField(False) + rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, title="Rules" ) @@ -35,14 +35,14 @@ class ImageIOFileRulesModel(BaseSettingsModel): class TrayPublisherImageIOModel(BaseSettingsModel): - activate_host_color_management: bool = Field( + activate_host_color_management: bool = SettingsField( True, title="Enable Color Management" ) - ocio_config: ImageIOConfigModel = Field( + ocio_config: ImageIOConfigModel = SettingsField( default_factory=ImageIOConfigModel, title="OCIO config" ) - file_rules: ImageIOFileRulesModel = Field( + file_rules: ImageIOFileRulesModel = SettingsField( default_factory=ImageIOFileRulesModel, title="File Rules" ) diff --git a/server_addon/traypublisher/server/settings/main.py b/server_addon/traypublisher/server/settings/main.py index fad96bef2f..760c529f49 100644 --- a/server_addon/traypublisher/server/settings/main.py +++ b/server_addon/traypublisher/server/settings/main.py @@ -1,5 +1,4 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField from .imageio import TrayPublisherImageIOModel from .simple_creators import ( @@ -22,23 +21,23 @@ from .publish_plugins import ( class TraypublisherSettings(BaseSettingsModel): """Traypublisher Project Settings.""" - imageio: TrayPublisherImageIOModel = Field( + imageio: TrayPublisherImageIOModel = SettingsField( default_factory=TrayPublisherImageIOModel, title="Color Management (ImageIO)" ) - simple_creators: list[SimpleCreatorPlugin] = Field( + simple_creators: list[SimpleCreatorPlugin] = SettingsField( title="Simple Create Plugins", default_factory=SimpleCreatorPlugin, ) - editorial_creators: TraypublisherEditorialCreatorPlugins = Field( + editorial_creators: TraypublisherEditorialCreatorPlugins = SettingsField( title="Editorial Creators", default_factory=TraypublisherEditorialCreatorPlugins, ) - create: TrayPublisherCreatePluginsModel = Field( + create: TrayPublisherCreatePluginsModel = SettingsField( title="Create", default_factory=TrayPublisherCreatePluginsModel ) - publish: TrayPublisherPublishPlugins = Field( + publish: TrayPublisherPublishPlugins = SettingsField( title="Publish Plugins", default_factory=TrayPublisherPublishPlugins ) diff --git a/server_addon/traypublisher/server/settings/publish_plugins.py b/server_addon/traypublisher/server/settings/publish_plugins.py index 8c844f29f2..f413c86227 100644 --- a/server_addon/traypublisher/server/settings/publish_plugins.py +++ b/server_addon/traypublisher/server/settings/publish_plugins.py @@ -1,13 +1,11 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class ValidatePluginModel(BaseSettingsModel): _isGroup = True enabled: bool = True - optional: bool = Field(True, title="Optional") - active: bool = Field(True, title="Active") + optional: bool = SettingsField(True, title="Optional") + active: bool = SettingsField(True, title="Active") class ValidateFrameRangeModel(ValidatePluginModel): @@ -17,15 +15,15 @@ class ValidateFrameRangeModel(ValidatePluginModel): class TrayPublisherPublishPlugins(BaseSettingsModel): - CollectFrameDataFromAssetEntity: ValidatePluginModel = Field( + CollectFrameDataFromAssetEntity: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Collect Frame Data From Folder Entity", ) - ValidateFrameRange: ValidateFrameRangeModel = Field( + ValidateFrameRange: ValidateFrameRangeModel = SettingsField( title="Validate Frame Range", default_factory=ValidateFrameRangeModel, ) - ValidateExistingVersion: ValidatePluginModel = Field( + ValidateExistingVersion: ValidatePluginModel = SettingsField( title="Validate Existing Version", default_factory=ValidatePluginModel, ) diff --git a/server_addon/traypublisher/server/settings/simple_creators.py b/server_addon/traypublisher/server/settings/simple_creators.py index 8335b9d34e..924eeedd23 100644 --- a/server_addon/traypublisher/server/settings/simple_creators.py +++ b/server_addon/traypublisher/server/settings/simple_creators.py @@ -1,42 +1,40 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class SimpleCreatorPlugin(BaseSettingsModel): _layout = "expanded" - product_type: str = Field("", title="Product type") + product_type: str = SettingsField("", title="Product type") # TODO add placeholder - identifier: str = Field("", title="Identifier") - label: str = Field("", title="Label") - icon: str = Field("", title="Icon") - default_variants: list[str] = Field( + identifier: str = SettingsField("", title="Identifier") + label: str = SettingsField("", title="Label") + icon: str = SettingsField("", title="Icon") + default_variants: list[str] = SettingsField( default_factory=list, title="Default Variants" ) - description: str = Field( + description: str = SettingsField( "", title="Description", widget="textarea" ) - detailed_description: str = Field( + detailed_description: str = SettingsField( "", title="Detailed Description", widget="textarea" ) - allow_sequences: bool = Field( + allow_sequences: bool = SettingsField( False, title="Allow sequences" ) - allow_multiple_items: bool = Field( + allow_multiple_items: bool = SettingsField( False, title="Allow multiple items" ) - allow_version_control: bool = Field( + allow_version_control: bool = SettingsField( False, title="Allow version control" ) - extensions: list[str] = Field( + extensions: list[str] = SettingsField( default_factory=list, title="Extensions" ) diff --git a/server_addon/tvpaint/server/settings/create_plugins.py b/server_addon/tvpaint/server/settings/create_plugins.py index 349bfdd288..b3351dca28 100644 --- a/server_addon/tvpaint/server/settings/create_plugins.py +++ b/server_addon/tvpaint/server/settings/create_plugins.py @@ -1,44 +1,43 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class CreateWorkfileModel(BaseSettingsModel): - enabled: bool = Field(True) - default_variant: str = Field(title="Default variant") - default_variants: list[str] = Field( + enabled: bool = SettingsField(True) + default_variant: str = SettingsField(title="Default variant") + default_variants: list[str] = SettingsField( default_factory=list, title="Default variants") class CreateReviewModel(BaseSettingsModel): - enabled: bool = Field(True) - active_on_create: bool = Field(True, title="Active by default") - default_variant: str = Field(title="Default variant") - default_variants: list[str] = Field( + enabled: bool = SettingsField(True) + active_on_create: bool = SettingsField(True, title="Active by default") + default_variant: str = SettingsField(title="Default variant") + default_variants: list[str] = SettingsField( default_factory=list, title="Default variants") class CreateRenderSceneModel(BaseSettingsModel): - enabled: bool = Field(True) - active_on_create: bool = Field(True, title="Active by default") - mark_for_review: bool = Field(True, title="Review by default") - default_pass_name: str = Field(title="Default beauty pass") - default_variant: str = Field(title="Default variant") - default_variants: list[str] = Field( + enabled: bool = SettingsField(True) + active_on_create: bool = SettingsField(True, title="Active by default") + mark_for_review: bool = SettingsField(True, title="Review by default") + default_pass_name: str = SettingsField(title="Default beauty pass") + default_variant: str = SettingsField(title="Default variant") + default_variants: list[str] = SettingsField( default_factory=list, title="Default variants") class CreateRenderLayerModel(BaseSettingsModel): - mark_for_review: bool = Field(True, title="Review by default") - default_pass_name: str = Field(title="Default beauty pass") - default_variant: str = Field(title="Default variant") - default_variants: list[str] = Field( + mark_for_review: bool = SettingsField(True, title="Review by default") + default_pass_name: str = SettingsField(title="Default beauty pass") + default_variant: str = SettingsField(title="Default variant") + default_variants: list[str] = SettingsField( default_factory=list, title="Default variants") class CreateRenderPassModel(BaseSettingsModel): - mark_for_review: bool = Field(True, title="Review by default") - default_variant: str = Field(title="Default variant") - default_variants: list[str] = Field( + mark_for_review: bool = SettingsField(True, title="Review by default") + default_variant: str = SettingsField(title="Default variant") + default_variants: list[str] = SettingsField( default_factory=list, title="Default variants") @@ -58,35 +57,39 @@ class AutoDetectCreateRenderModel(BaseSettingsModel): Would create group names "L010", "L020", ... """ - enabled: bool = Field(True) - allow_group_rename: bool = Field(title="Allow group rename") - group_name_template: str = Field(title="Group name template") - group_idx_offset: int = Field(1, title="Group index Offset", ge=1) - group_idx_padding: int = Field(4, title="Group index Padding", ge=1) + enabled: bool = SettingsField(True) + allow_group_rename: bool = SettingsField(title="Allow group rename") + group_name_template: str = SettingsField(title="Group name template") + group_idx_offset: int = SettingsField( + 1, title="Group index Offset", ge=1 + ) + group_idx_padding: int = SettingsField( + 4, title="Group index Padding", ge=1 + ) class CreatePluginsModel(BaseSettingsModel): - create_workfile: CreateWorkfileModel = Field( + create_workfile: CreateWorkfileModel = SettingsField( default_factory=CreateWorkfileModel, title="Create Workfile" ) - create_review: CreateReviewModel = Field( + create_review: CreateReviewModel = SettingsField( default_factory=CreateReviewModel, title="Create Review" ) - create_render_scene: CreateRenderSceneModel = Field( + create_render_scene: CreateRenderSceneModel = SettingsField( default_factory=CreateReviewModel, title="Create Render Scene" ) - create_render_layer: CreateRenderLayerModel= Field( + create_render_layer: CreateRenderLayerModel = SettingsField( default_factory=CreateRenderLayerModel, title="Create Render Layer" ) - create_render_pass: CreateRenderPassModel = Field( + create_render_pass: CreateRenderPassModel = SettingsField( default_factory=CreateRenderPassModel, title="Create Render Pass" ) - auto_detect_render: AutoDetectCreateRenderModel = Field( + auto_detect_render: AutoDetectCreateRenderModel = SettingsField( default_factory=AutoDetectCreateRenderModel, title="Auto-Detect Create Render", ) diff --git a/server_addon/tvpaint/server/settings/filters.py b/server_addon/tvpaint/server/settings/filters.py index 009febae06..9720e82281 100644 --- a/server_addon/tvpaint/server/settings/filters.py +++ b/server_addon/tvpaint/server/settings/filters.py @@ -1,12 +1,10 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField class FiltersSubmodel(BaseSettingsModel): _layout = "compact" - name: str = Field(title="Name") - value: str = Field( + name: str = SettingsField(title="Name") + value: str = SettingsField( "", title="Textarea", widget="textarea", @@ -14,6 +12,6 @@ class FiltersSubmodel(BaseSettingsModel): class PublishFiltersModel(BaseSettingsModel): - env_search_replace_values: list[FiltersSubmodel] = Field( + env_search_replace_values: list[FiltersSubmodel] = SettingsField( default_factory=list ) diff --git a/server_addon/tvpaint/server/settings/imageio.py b/server_addon/tvpaint/server/settings/imageio.py index 50f8b7eef4..aaf3fbf34e 100644 --- a/server_addon/tvpaint/server/settings/imageio.py +++ b/server_addon/tvpaint/server/settings/imageio.py @@ -1,29 +1,29 @@ -from pydantic import Field, validator -from ayon_server.settings import BaseSettingsModel +from pydantic import validator +from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.settings.validators import ensure_unique_names class ImageIOConfigModel(BaseSettingsModel): - override_global_config: bool = Field( + override_global_config: bool = SettingsField( False, title="Override global OCIO config" ) - filepath: list[str] = Field( + filepath: list[str] = SettingsField( default_factory=list, title="Config path" ) class ImageIOFileRuleModel(BaseSettingsModel): - name: str = Field("", title="Rule name") - pattern: str = Field("", title="Regex pattern") - colorspace: str = Field("", title="Colorspace name") - ext: str = Field("", title="File extension") + name: str = SettingsField("", title="Rule name") + pattern: str = SettingsField("", title="Regex pattern") + colorspace: str = SettingsField("", title="Colorspace name") + ext: str = SettingsField("", title="File extension") class ImageIOFileRulesModel(BaseSettingsModel): - activate_host_rules: bool = Field(False) - rules: list[ImageIOFileRuleModel] = Field( + activate_host_rules: bool = SettingsField(False) + rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, title="Rules" ) @@ -35,14 +35,14 @@ class ImageIOFileRulesModel(BaseSettingsModel): class TVPaintImageIOModel(BaseSettingsModel): - activate_host_color_management: bool = Field( + activate_host_color_management: bool = SettingsField( True, title="Enable Color Management" ) - ocio_config: ImageIOConfigModel = Field( + ocio_config: ImageIOConfigModel = SettingsField( default_factory=ImageIOConfigModel, title="OCIO config" ) - file_rules: ImageIOFileRulesModel = Field( + file_rules: ImageIOFileRulesModel = SettingsField( default_factory=ImageIOFileRulesModel, title="File Rules" ) diff --git a/server_addon/tvpaint/server/settings/main.py b/server_addon/tvpaint/server/settings/main.py index 102acfaf3d..c6b6c9ab12 100644 --- a/server_addon/tvpaint/server/settings/main.py +++ b/server_addon/tvpaint/server/settings/main.py @@ -1,6 +1,6 @@ -from pydantic import Field from ayon_server.settings import ( BaseSettingsModel, + SettingsField, ensure_unique_names, ) @@ -15,23 +15,23 @@ from .publish_plugins import ( class TvpaintSettings(BaseSettingsModel): - imageio: TVPaintImageIOModel = Field( + imageio: TVPaintImageIOModel = SettingsField( default_factory=TVPaintImageIOModel, title="Color Management (ImageIO)" ) - stop_timer_on_application_exit: bool = Field( + stop_timer_on_application_exit: bool = SettingsField( title="Stop timer on application exit") - create: CreatePluginsModel = Field( + create: CreatePluginsModel = SettingsField( default_factory=CreatePluginsModel, title="Create plugins" ) - publish: PublishPluginsModel = Field( + publish: PublishPluginsModel = SettingsField( default_factory=PublishPluginsModel, title="Publish plugins") - load: LoadPluginsModel = Field( + load: LoadPluginsModel = SettingsField( default_factory=LoadPluginsModel, title="Load plugins") - workfile_builder: WorkfileBuilderPlugin = Field( + workfile_builder: WorkfileBuilderPlugin = SettingsField( default_factory=WorkfileBuilderPlugin, title="Workfile Builder" ) diff --git a/server_addon/tvpaint/server/settings/publish_plugins.py b/server_addon/tvpaint/server/settings/publish_plugins.py index 76c7eaac01..0623524c92 100644 --- a/server_addon/tvpaint/server/settings/publish_plugins.py +++ b/server_addon/tvpaint/server/settings/publish_plugins.py @@ -1,11 +1,9 @@ -from pydantic import Field - -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.types import ColorRGBA_uint8 class CollectRenderInstancesModel(BaseSettingsModel): - ignore_render_pass_transparency: bool = Field( + ignore_render_pass_transparency: bool = SettingsField( title="Ignore Render Pass opacity" ) @@ -13,15 +11,15 @@ class CollectRenderInstancesModel(BaseSettingsModel): class ExtractSequenceModel(BaseSettingsModel): """Review BG color is used for whole scene review and for thumbnails.""" # TODO Use alpha color - review_bg: ColorRGBA_uint8 = Field( + review_bg: ColorRGBA_uint8 = SettingsField( (255, 255, 255, 1.0), title="Review BG color") class ValidatePluginModel(BaseSettingsModel): enabled: bool = True - optional: bool = Field(True, title="Optional") - active: bool = Field(True, title="Active") + optional: bool = SettingsField(True, title="Optional") + active: bool = SettingsField(True, title="Active") def compression_enum(): @@ -44,7 +42,7 @@ class ExtractConvertToEXRModel(BaseSettingsModel): enabled: bool = False replace_pngs: bool = True - exr_compression: str = Field( + exr_compression: str = SettingsField( "ZIP", enum_resolver=compression_enum, title="EXR Compression" @@ -53,46 +51,46 @@ class ExtractConvertToEXRModel(BaseSettingsModel): class LoadImageDefaultModel(BaseSettingsModel): _layout = "expanded" - stretch: bool = Field(title="Stretch") - timestretch: bool = Field(title="TimeStretch") - preload: bool = Field(title="Preload") + stretch: bool = SettingsField(title="Stretch") + timestretch: bool = SettingsField(title="TimeStretch") + preload: bool = SettingsField(title="Preload") class LoadImageModel(BaseSettingsModel): - defaults: LoadImageDefaultModel = Field( + defaults: LoadImageDefaultModel = SettingsField( default_factory=LoadImageDefaultModel ) class PublishPluginsModel(BaseSettingsModel): - CollectRenderInstances: CollectRenderInstancesModel = Field( + CollectRenderInstances: CollectRenderInstancesModel = SettingsField( default_factory=CollectRenderInstancesModel, title="Collect Render Instances") - ExtractSequence: ExtractSequenceModel = Field( + ExtractSequence: ExtractSequenceModel = SettingsField( default_factory=ExtractSequenceModel, title="Extract Sequence") - ValidateProjectSettings: ValidatePluginModel = Field( + ValidateProjectSettings: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Validate Project Settings") - ValidateMarks: ValidatePluginModel = Field( + ValidateMarks: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Validate MarkIn/Out") - ValidateStartFrame: ValidatePluginModel = Field( + ValidateStartFrame: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Validate Scene Start Frame") - ValidateAssetName: ValidatePluginModel = Field( + ValidateAssetName: ValidatePluginModel = SettingsField( default_factory=ValidatePluginModel, title="Validate Folder Name") - ExtractConvertToEXR: ExtractConvertToEXRModel = Field( + ExtractConvertToEXR: ExtractConvertToEXRModel = SettingsField( default_factory=ExtractConvertToEXRModel, title="Extract Convert To EXR") class LoadPluginsModel(BaseSettingsModel): - LoadImage: LoadImageModel = Field( + LoadImage: LoadImageModel = SettingsField( default_factory=LoadImageModel, title="Load Image") - ImportImage: LoadImageModel = Field( + ImportImage: LoadImageModel = SettingsField( default_factory=LoadImageModel, title="Import Image") diff --git a/server_addon/tvpaint/server/settings/workfile_builder.py b/server_addon/tvpaint/server/settings/workfile_builder.py index e0aba5da7e..0799497bf9 100644 --- a/server_addon/tvpaint/server/settings/workfile_builder.py +++ b/server_addon/tvpaint/server/settings/workfile_builder.py @@ -1,30 +1,29 @@ -from pydantic import Field - from ayon_server.settings import ( BaseSettingsModel, + SettingsField, MultiplatformPathModel, task_types_enum, ) class CustomBuilderTemplate(BaseSettingsModel): - task_types: list[str] = Field( + task_types: list[str] = SettingsField( default_factory=list, title="Task types", enum_resolver=task_types_enum ) - template_path: MultiplatformPathModel = Field( + template_path: MultiplatformPathModel = SettingsField( default_factory=MultiplatformPathModel ) class WorkfileBuilderPlugin(BaseSettingsModel): _title = "Workfile Builder" - create_first_version: bool = Field( + create_first_version: bool = SettingsField( False, title="Create first workfile" ) - custom_templates: list[CustomBuilderTemplate] = Field( + custom_templates: list[CustomBuilderTemplate] = SettingsField( default_factory=CustomBuilderTemplate ) diff --git a/server_addon/unreal/server/imageio.py b/server_addon/unreal/server/imageio.py index dde042ba47..853d476587 100644 --- a/server_addon/unreal/server/imageio.py +++ b/server_addon/unreal/server/imageio.py @@ -1,29 +1,29 @@ -from pydantic import Field, validator -from ayon_server.settings import BaseSettingsModel +from pydantic import validator +from ayon_server.settings import BaseSettingsModel, SettingsField from ayon_server.settings.validators import ensure_unique_names class ImageIOConfigModel(BaseSettingsModel): - override_global_config: bool = Field( + override_global_config: bool = SettingsField( False, title="Override global OCIO config" ) - filepath: list[str] = Field( + filepath: list[str] = SettingsField( default_factory=list, title="Config path" ) class ImageIOFileRuleModel(BaseSettingsModel): - name: str = Field("", title="Rule name") - pattern: str = Field("", title="Regex pattern") - colorspace: str = Field("", title="Colorspace name") - ext: str = Field("", title="File extension") + name: str = SettingsField("", title="Rule name") + pattern: str = SettingsField("", title="Regex pattern") + colorspace: str = SettingsField("", title="Colorspace name") + ext: str = SettingsField("", title="File extension") class ImageIOFileRulesModel(BaseSettingsModel): - activate_host_rules: bool = Field(False) - rules: list[ImageIOFileRuleModel] = Field( + activate_host_rules: bool = SettingsField(False) + rules: list[ImageIOFileRuleModel] = SettingsField( default_factory=list, title="Rules" ) @@ -35,14 +35,14 @@ class ImageIOFileRulesModel(BaseSettingsModel): class UnrealImageIOModel(BaseSettingsModel): - activate_host_color_management: bool = Field( + activate_host_color_management: bool = SettingsField( True, title="Enable Color Management" ) - ocio_config: ImageIOConfigModel = Field( + ocio_config: ImageIOConfigModel = SettingsField( default_factory=ImageIOConfigModel, title="OCIO config" ) - file_rules: ImageIOFileRulesModel = Field( + file_rules: ImageIOFileRulesModel = SettingsField( default_factory=ImageIOFileRulesModel, title="File Rules" ) diff --git a/server_addon/unreal/server/settings.py b/server_addon/unreal/server/settings.py index 110ccc563a..5f54fb6c75 100644 --- a/server_addon/unreal/server/settings.py +++ b/server_addon/unreal/server/settings.py @@ -1,11 +1,10 @@ -from pydantic import Field -from ayon_server.settings import BaseSettingsModel +from ayon_server.settings import BaseSettingsModel, SettingsField from .imageio import UnrealImageIOModel class ProjectSetup(BaseSettingsModel): - dev_mode: bool = Field( + dev_mode: bool = SettingsField( False, title="Dev mode" ) @@ -21,32 +20,32 @@ def _render_format_enum(): class UnrealSettings(BaseSettingsModel): - imageio: UnrealImageIOModel = Field( + imageio: UnrealImageIOModel = SettingsField( default_factory=UnrealImageIOModel, title="Color Management (ImageIO)" ) - level_sequences_for_layouts: bool = Field( + level_sequences_for_layouts: bool = SettingsField( False, title="Generate level sequences when loading layouts" ) - delete_unmatched_assets: bool = Field( + delete_unmatched_assets: bool = SettingsField( False, title="Delete assets that are not matched" ) - render_config_path: str = Field( + render_config_path: str = SettingsField( "", title="Render Config Path" ) - preroll_frames: int = Field( + preroll_frames: int = SettingsField( 0, title="Pre-roll frames" ) - render_format: str = Field( + render_format: str = SettingsField( "png", title="Render format", enum_resolver=_render_format_enum ) - project_setup: ProjectSetup = Field( + project_setup: ProjectSetup = SettingsField( default_factory=ProjectSetup, title="Project Setup", ) diff --git a/start.py b/start.py index 54a252ccf3..e4ada05822 100644 --- a/start.py +++ b/start.py @@ -1186,10 +1186,6 @@ def get_info(use_staging=None) -> list: inf.append(("Using Deadline webservice at", os.environ.get("DEADLINE_REST_URL"))) - if os.environ.get('MUSTER_REST_URL'): - inf.append(("Using Muster at", - os.environ.get("MUSTER_REST_URL"))) - # Reinitialize Logger.initialize() diff --git a/website/docs/admin_settings_system.md b/website/docs/admin_settings_system.md index 8abcefd24d..aefeaf893a 100644 --- a/website/docs/admin_settings_system.md +++ b/website/docs/admin_settings_system.md @@ -95,13 +95,6 @@ Disable/Enable Standalone Publisher option **`Deadline Rest URL`** - URL to deadline webservice that. This URL must be reachable from every workstation that should be submitting render jobs to deadline via OpenPype. -### Muster - -**`Muster Rest URL`** - URL to Muster webservice that. This URL must be reachable from every -workstation that should be submitting render jobs to muster via OpenPype. - -**`templates mapping`** - you can customize Muster templates to match your existing setup here. - ### Royal Render **`Royal Render Root Paths`** - multi platform paths to Royal Render installation. diff --git a/website/docs/artist_hosts_maya.md b/website/docs/artist_hosts_maya.md index e36ccb77d2..364461f4b6 100644 --- a/website/docs/artist_hosts_maya.md +++ b/website/docs/artist_hosts_maya.md @@ -386,14 +386,11 @@ models you've put into layout. OpenPype in Maya can be used for submitting renders to render farm and for their subsequent publishing. Right now OpenPype support [AWS Thinkbox Deadline](https://www.awsthinkbox.com/deadline) -and [Virtual Vertex Muster](https://www.vvertex.com/overview/). +and [Royal Render](https://www.royalrender.de/). -* For setting up Muster support see [admin section](module_muster.md) +* For setting up Royal Render support see [admin section](module_royalrender.md) * For setting up Deadline support see [here](module_deadline.md) -:::note Muster login -Muster is now configured so every user must log in to get authentication support. If OpenPype founds out this token is missing or expired, it will ask again for credentials. -::: ### Creating basic render setup @@ -436,12 +433,7 @@ checked **Use selection** it will use your current Render Layers (if you have th if no render layers is present in scene, it will create one for you named **Main** and under it default collection with `*` selector. -No matter if you use *Deadline* or *Muster*, OpenPype will try to connect to render farm and -fetch machine pool list. - -:::note Muster login -This might fail on *Muster* in the event that you have expired authentication token. In that case, you'll be presented with login window. Nothing will be created in the scene until you log in again and do create **Render** again. -::: +OpenPype will try to connect to render farm and fetch machine pool list. So now my scene now looks like this: diff --git a/website/docs/dev_settings.md b/website/docs/dev_settings.md index 1010169a5f..831536c460 100644 --- a/website/docs/dev_settings.md +++ b/website/docs/dev_settings.md @@ -34,7 +34,7 @@ As was mentioned schema items define output type of values, how they are stored - `"is_file"` - this key is used when defaults values are stored in the file. Its value matches the filename where values are stored - key is validated, must be unique in hierarchy otherwise it won't be possible to store default values - make sense to fill it only if it's value if `true` - + - `"is_group"` - define that all values under a key in settings hierarchy will be overridden if any value is modified - this key is not allowed for all inputs as they may not have technical ability to handle it - key is validated, must be unique in hierarchy and is automatically filled on last possible item if is not defined in schemas @@ -710,7 +710,7 @@ How output of the schema could look like on save: "object_type": "text", "is_group": true, "key": "templates_mapping", - "label": "Muster - Templates mapping", + "label": "Deadline - Templates mapping", "is_file": true } ``` @@ -726,7 +726,7 @@ How output of the schema could look like on save: }, "is_group": true, "key": "templates_mapping", - "label": "Muster - Templates mapping", + "label": "Deadline - Templates mapping", "is_file": true } ``` diff --git a/website/docs/features.md b/website/docs/features.md index fd6196f71f..43fd522346 100644 --- a/website/docs/features.md +++ b/website/docs/features.md @@ -238,17 +238,11 @@ Create preview quicktimes from rendered frames publish rendered outputs to Avalon and Ftrack - ## Muster - -Publish to deadline from - +## Royal Render +Publish to Royal Render from Maya - Nuke -Create preview quicktimes from rendered frames - -publish rendered outputs to Avalon and Ftrack ## Clockify diff --git a/website/docs/module_muster.md b/website/docs/module_muster.md deleted file mode 100644 index 28c4b33aa8..0000000000 --- a/website/docs/module_muster.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -id: module_muster -title: Muster Administration -sidebar_label: Muster ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - - diff --git a/website/docs/pype2/admin_hosts.md b/website/docs/pype2/admin_hosts.md index 24efef7f05..f7aa5bd54a 100644 --- a/website/docs/pype2/admin_hosts.md +++ b/website/docs/pype2/admin_hosts.md @@ -157,6 +157,10 @@ machine setup on farm. If there is no mix of windows/linux machines on farm, the ## Virtual Vertex Muster +:::warning +Support for Muster was removed from OpenPype and AYON. +::: + Pype supports rendering with [Muster](https://www.vvertex.com/). To enable it: 1. Add `muster` to **init_env** to your `deploy.json` file: diff --git a/website/sidebars.js b/website/sidebars.js index b885181fb6..0d151433ea 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -110,7 +110,6 @@ module.exports = { "module_kitsu", "module_site_sync", "module_deadline", - "module_muster", "module_royalrender", "module_clockify", "module_slack" diff --git a/website/src/pages/index.js b/website/src/pages/index.js index 52302ec285..92ed404c35 100644 --- a/website/src/pages/index.js +++ b/website/src/pages/index.js @@ -29,7 +29,7 @@ const services = [ title: <>Extensible, description: ( <> - Project needs differ, clients differ and studios differ. OpenPype is designed to fit into your workflow and bend to your will. If a feature is missing, it can most probably be added. + Project needs differ, clients differ and studios differ. OpenPype is designed to fit into your workflow and bend to your will. If a feature is missing, it can most probably be added. ), }, @@ -310,7 +310,7 @@ function Home() {

Why choose openPype?

- Pipeline is the technical backbone of your production. It means, that whatever solution you use, it will cause vendor-lock to some extend. + Pipeline is the technical backbone of your production. It means, that whatever solution you use, it will cause vendor-lock to some extend. You can mitigate this risk by developing purely in-house tools, however, that just shifts the problem from a software vendor to your developers. Sooner or later, you'll hit the limits of such solution. In-house tools tend to be undocumented, narrow focused and heavily dependent on a very few or even a single developer.

@@ -332,7 +332,7 @@ function Home() { Maya - + Flame @@ -422,7 +422,7 @@ function Home() { Deadline - + Royal Render @@ -443,17 +443,12 @@ function Home() {

Planned or in development by us and OpenPype community.