From 8002dc4f4fb937edb07336232285e48bfec59989 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Mon, 20 Feb 2023 21:29:11 +0800 Subject: [PATCH] style fix --- openpype/hosts/max/api/lib.py | 38 ++- openpype/hosts/max/api/lib_renderproducts.py | 70 ++---- openpype/hosts/max/api/lib_rendersettings.py | 5 +- .../hosts/max/plugins/create/create_render.py | 2 +- .../max/plugins/publish/collect_render.py | 6 +- .../plugins/publish/submit_3dmax_deadline.py | 237 ------------------ .../plugins/publish/submit_max_deadline.py | 217 ++++++++++++++++ .../defaults/project_settings/deadline.json | 4 +- .../schema_project_deadline.json | 2 +- 9 files changed, 275 insertions(+), 306 deletions(-) delete mode 100644 openpype/modules/deadline/plugins/publish/submit_3dmax_deadline.py create mode 100644 openpype/modules/deadline/plugins/publish/submit_max_deadline.py diff --git a/openpype/hosts/max/api/lib.py b/openpype/hosts/max/api/lib.py index ecea8b5541..14aa4d750a 100644 --- a/openpype/hosts/max/api/lib.py +++ b/openpype/hosts/max/api/lib.py @@ -134,19 +134,21 @@ def get_default_render_folder(project_setting=None): def set_framerange(startFrame, endFrame): - """Get/set the type of time range to be rendered. - - Possible values are: - - 1 -Single frame. - - 2 -Active time segment ( animationRange ). - - 3 -User specified Range. - - 4 -User specified Frame pickup string (for example "1,3,5-12"). """ - # hard-code, there should be a custom setting for this + Args: + start_frame (int): Start frame number. + end_frame (int): End frame number. + Note: + Frame range can be specified in different types. Possible values are: + + * `1` - Single frame. + * `2` - Active time segment ( animationRange ). + * `3` - User specified Range. + * `4` - User specified Frame pickup string (for example `1,3,5-12`). + + Todo: + Current type is hard-coded, there should be a custom setting for this. + """ rt.rendTimeType = 4 if startFrame is not None and endFrame is not None: frameRange = "{0}-{1}".format(startFrame, endFrame) @@ -157,3 +159,15 @@ def get_multipass_setting(project_setting=None): return (project_setting["max"] ["RenderSettings"] ["multipass"]) + +def get_max_version(): + """ + Args: + get max version date for deadline + + Returns: + #(25000, 62, 0, 25, 0, 0, 997, 2023, "") + max_info[7] = max version date + """ + max_info = rt.maxversion() + return max_info[7] diff --git a/openpype/hosts/max/api/lib_renderproducts.py b/openpype/hosts/max/api/lib_renderproducts.py index e09934e5de..00e0978bc8 100644 --- a/openpype/hosts/max/api/lib_renderproducts.py +++ b/openpype/hosts/max/api/lib_renderproducts.py @@ -15,7 +15,6 @@ from openpype.pipeline import legacy_io class RenderProducts(object): - @classmethod def __init__(self, project_settings=None): self._project_settings = project_settings if not self._project_settings: @@ -36,15 +35,11 @@ class RenderProducts(object): filename, container) - context = get_current_project_asset() - startFrame = context["data"].get("frameStart") - endFrame = context["data"].get("frameEnd") + 1 - img_fmt = self._project_settings["max"]["RenderSettings"]["image_format"] # noqa - full_render_list = self.beauty_render_product(output_file, - startFrame, - endFrame, - img_fmt) + full_render_list = [] + beauty = self.beauty_render_product(output_file, img_fmt) + full_render_list.append(beauty) + renderer_class = get_current_renderer() renderer = str(renderer_class).split(":")[0] @@ -60,41 +55,29 @@ class RenderProducts(object): renderer == "Quicksilver_Hardware_Renderer" ): render_elem_list = self.render_elements_product(output_file, - startFrame, - endFrame, img_fmt) - for render_elem in render_elem_list: - full_render_list.append(render_elem) + if render_elem_list: + for render_elem in render_elem_list: + full_render_list.append(render_elem) return full_render_list if renderer == "Arnold": aov_list = self.arnold_render_product(output_file, - startFrame, - endFrame, img_fmt) if aov_list: for aov in aov_list: full_render_list.append(aov) return full_render_list - def beauty_render_product(self, folder, startFrame, endFrame, fmt): - # get the beauty - beauty_frame_range = list() - - for f in range(startFrame, endFrame): - beauty = "{0}.{1}.{2}".format(folder, - str(f), - fmt) - beauty = beauty.replace("\\", "/") - beauty_frame_range.append(beauty) - - return beauty_frame_range - + def beauty_render_product(self, folder, fmt): + beauty_output = f"{folder}.####.{fmt}" + beauty_output = beauty_output.replace("\\", "/") + return beauty_output # TODO: Get the arnold render product - def arnold_render_product(self, folder, startFrame, endFrame, fmt): + def arnold_render_product(self, folder, fmt): """Get all the Arnold AOVs""" - aovs = list() + aovs = [] amw = rt.MaxtoAOps.AOVsManagerWindow() aov_mgr = rt.renderers.current.AOVManager @@ -105,21 +88,17 @@ class RenderProducts(object): for i in range(aov_group_num): # get the specific AOV group for aov in aov_mgr.drivers[i].aov_list: - for f in range(startFrame, endFrame): - render_element = "{0}_{1}.{2}.{3}".format(folder, - str(aov.name), - str(f), - fmt) - render_element = render_element.replace("\\", "/") - aovs.append(render_element) + render_element = f"{folder}_{aov.name}.####.{fmt}" + render_element = render_element.replace("\\", "/") + aovs.append(render_element) # close the AOVs manager window amw.close() return aovs - def render_elements_product(self, folder, startFrame, endFrame, fmt): + def render_elements_product(self, folder, fmt): """Get all the render element output files. """ - render_dirname = list() + render_dirname = [] render_elem = rt.maxOps.GetCurRenderElementMgr() render_elem_num = render_elem.NumRenderElements() @@ -128,16 +107,11 @@ class RenderProducts(object): renderlayer_name = render_elem.GetRenderElement(i) target, renderpass = str(renderlayer_name).split(":") if renderlayer_name.enabled: - for f in range(startFrame, endFrame): - render_element = "{0}_{1}.{2}.{3}".format(folder, - renderpass, - str(f), - fmt) - render_element = render_element.replace("\\", "/") - render_dirname.append(render_element) + render_element = f"{folder}_{renderpass}.####.{fmt}" + render_element = render_element.replace("\\", "/") + render_dirname.append(render_element) return render_dirname def image_format(self): - img_fmt = self._project_settings["max"]["RenderSettings"]["image_format"] # noqa - return img_fmt + return self._project_settings["max"]["RenderSettings"]["image_format"] # noqa diff --git a/openpype/hosts/max/api/lib_rendersettings.py b/openpype/hosts/max/api/lib_rendersettings.py index 92f716ba54..212c08846b 100644 --- a/openpype/hosts/max/api/lib_rendersettings.py +++ b/openpype/hosts/max/api/lib_rendersettings.py @@ -22,7 +22,6 @@ class RenderSettings(object): "underscore": "_" } - @classmethod def __init__(self, project_settings=None): self._project_settings = project_settings if not self._project_settings: @@ -41,7 +40,7 @@ class RenderSettings(object): if not found: raise RuntimeError("Camera not found") - def set_renderoutput(self, container): + def render_output(self, container): folder = rt.maxFilePath # hard-coded, should be customized in the setting file = rt.maxFileName @@ -144,7 +143,7 @@ class RenderSettings(object): aov_name = "{0}_{1}..{2}".format(dir, renderpass, ext) render_elem.SetRenderElementFileName(i, aov_name) - def get_renderoutput(self, container, output_dir): + def get_render_output(self, container, output_dir): output = os.path.join(output_dir, container) img_fmt = self._project_settings["max"]["RenderSettings"]["image_format"] # noqa outputFilename = "{0}..{1}".format(output, img_fmt) diff --git a/openpype/hosts/max/plugins/create/create_render.py b/openpype/hosts/max/plugins/create/create_render.py index 76c10ca4a9..269fff2e32 100644 --- a/openpype/hosts/max/plugins/create/create_render.py +++ b/openpype/hosts/max/plugins/create/create_render.py @@ -30,4 +30,4 @@ class CreateRender(plugin.MaxCreator): # set viewport camera for rendering(mandatory for deadline) RenderSettings().set_render_camera(sel_obj) # set output paths for rendering(mandatory for deadline) - RenderSettings().set_renderoutput(container_name) + RenderSettings().render_output(container_name) diff --git a/openpype/hosts/max/plugins/publish/collect_render.py b/openpype/hosts/max/plugins/publish/collect_render.py index 55391d40e8..16f8821986 100644 --- a/openpype/hosts/max/plugins/publish/collect_render.py +++ b/openpype/hosts/max/plugins/publish/collect_render.py @@ -4,7 +4,8 @@ import os import pyblish.api from pymxs import runtime as rt -from openpype.pipeline import legacy_io +from openpype.pipeline import get_current_asset_name +from openpype.hosts.max.api.lib import get_max_version from openpype.hosts.max.api.lib_renderproducts import RenderProducts from openpype.client import get_last_version_by_subset_name @@ -25,7 +26,7 @@ class CollectRender(pyblish.api.InstancePlugin): filepath = current_file.replace("\\", "/") context.data['currentFile'] = current_file - asset = legacy_io.Session["AVALON_ASSET"] + asset = get_current_asset_name() render_layer_files = RenderProducts().render_product(instance.name) folder = folder.replace("\\", "/") @@ -51,6 +52,7 @@ class CollectRender(pyblish.api.InstancePlugin): "subset": instance.name, "asset": asset, "publish": True, + "maxversion": str(get_max_version()), "imageFormat": imgFormat, "family": 'maxrender', "families": ['maxrender'], diff --git a/openpype/modules/deadline/plugins/publish/submit_3dmax_deadline.py b/openpype/modules/deadline/plugins/publish/submit_3dmax_deadline.py deleted file mode 100644 index ed448abe1f..0000000000 --- a/openpype/modules/deadline/plugins/publish/submit_3dmax_deadline.py +++ /dev/null @@ -1,237 +0,0 @@ -import os -import json -import getpass - -import requests -import pyblish.api - -from openpype.pipeline import legacy_io -from openpype.settings import get_project_settings -from openpype.hosts.max.api.lib import ( - get_current_renderer, - get_multipass_setting -) -from openpype.hosts.max.api.lib_rendersettings import RenderSettings - - -class MaxSubmitRenderDeadline(pyblish.api.InstancePlugin): - """ - 3DMax File Submit Render Deadline - - """ - - label = "Submit 3DsMax Render to Deadline" - order = pyblish.api.IntegratorOrder - hosts = ["max"] - families = ["maxrender"] - targets = ["local"] - use_published = True - priority = 50 - chunk_size = 1 - group = None - deadline_pool = None - deadline_pool_secondary = None - framePerTask = 1 - - def process(self, instance): - context = instance.context - filepath = context.data["currentFile"] - filename = os.path.basename(filepath) - comment = context.data.get("comment", "") - deadline_user = context.data.get("deadlineUser", getpass.getuser()) - jobname = "{0} - {1}".format(filename, instance.name) - - # StartFrame to EndFrame - frames = "{start}-{end}".format( - start=int(instance.data["frameStart"]), - end=int(instance.data["frameEnd"]) - ) - if self.use_published: - for item in context: - if "workfile" in item.data["families"]: - msg = "Workfile (scene) must be published along" - assert item.data["publish"] is True, msg - - 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_data = context.data["anatomy"] - anatomy_filled = anatomy_data.format(template_data) - template_filled = anatomy_filled["publish"]["path"] - filepath = os.path.normpath(template_filled) - filepath = filepath.replace("\\", "/") - self.log.info( - "Using published scene for render {}".format(filepath) - ) - if not os.path.exists(filepath): - self.log.error("published scene does not exist!") - - new_scene = self._clean_name(filepath) - # use the anatomy data for setting up the path of the files - orig_scene = self._clean_name(instance.context.data["currentFile"]) - expected_files = instance.data.get("expectedFiles") - - new_exp = [] - for file in expected_files: - new_file = str(file).replace(orig_scene, new_scene) - new_exp.append(new_file) - - instance.data["expectedFiles"] = new_exp - - metadata_folder = instance.data.get("publishRenderMetadataFolder") - if metadata_folder: - metadata_folder = metadata_folder.replace(orig_scene, - new_scene) - instance.data["publishRenderMetadataFolder"] = metadata_folder - - payload = { - "JobInfo": { - # Top-level group name - "BatchName": filename, - - # Job name, as seen in Monitor - "Name": jobname, - - # Arbitrary username, for visualisation in Monitor - "UserName": deadline_user, - - "Plugin": instance.data["plugin"], - "Group": self.group, - "Pool": self.deadline_pool, - "secondaryPool": self.deadline_pool_secondary, - "Frames": frames, - "ChunkSize": self.chunk_size, - "Priority": instance.data.get("priority", self.priority), - "Comment": comment, - "FramesPerTask": self.framePerTask - }, - "PluginInfo": { - # Input - "SceneFile": filepath, - "Version": "2023", - "SaveFile": True, - # Mandatory for Deadline - # Houdini version without patch number - - "IgnoreInputs": True - }, - - # Mandatory for Deadline, may be empty - "AuxFiles": [] - } - # Include critical environment variables with submission + api.Session - keys = [ - # Submit along the current Avalon tool setup that we launched - # this application with so the Render Slave can build its own - # similar environment using it, e.g. "maya2018;vray4.x;yeti3.1.9" - "AVALON_TOOLS", - "OPENPYPE_VERSION" - ] - # Add mongo url if it's enabled - if context.data.get("deadlinePassMongoUrl"): - keys.append("OPENPYPE_MONGO") - - environment = dict({key: os.environ[key] for key in keys - if key in os.environ}, **legacy_io.Session) - - payload["JobInfo"].update({ - "EnvironmentKeyValue%d" % index: "{key}={value}".format( - key=key, - value=environment[key] - ) for index, key in enumerate(environment) - }) - - # Include OutputFilename entries - # The first entry also enables double-click to preview rendered - # frames from Deadline Monitor - output_data = {} - # need to be fixed - for i, filepath in enumerate(instance.data["expectedFiles"]): - dirname = os.path.dirname(filepath) - fname = os.path.basename(filepath) - output_data["OutputDirectory%d" % i] = dirname.replace("\\", "/") - output_data["OutputFilename%d" % i] = fname - - if not os.path.exists(dirname): - self.log.info("Ensuring output directory exists: %s" % - dirname) - os.makedirs(dirname) - - plugin_data = {} - project_setting = get_project_settings( - legacy_io.Session["AVALON_PROJECT"] - ) - - multipass = get_multipass_setting(project_setting) - if multipass: - plugin_data["DisableMultipass"] = 0 - else: - plugin_data["DisableMultipass"] = 1 - - if self.use_published: - old_output_dir = os.path.dirname(expected_files[0]) - output_beauty = RenderSettings().get_renderoutput(instance.name, - old_output_dir) - output_beauty = output_beauty.replace(orig_scene, new_scene) - output_beauty = output_beauty.replace("\\", "/") - plugin_data["RenderOutput"] = output_beauty - - renderer_class = get_current_renderer() - renderer = str(renderer_class).split(":")[0] - if ( - renderer == "ART_Renderer" or - renderer == "Redshift_Renderer" or - renderer == "V_Ray_6_Hotfix_3" or - renderer == "V_Ray_GPU_6_Hotfix_3" or - renderer == "Default_Scanline_Renderer" or - renderer == "Quicksilver_Hardware_Renderer" - ): - render_elem_list = RenderSettings().get_render_element() - for i, element in enumerate(render_elem_list): - element = element.replace(orig_scene, new_scene) - plugin_data["RenderElementOutputFilename%d" % i] = element # noqa - - self.log.debug("plugin data:{}".format(plugin_data)) - self.log.info("Scene name was switched {} -> {}".format( - orig_scene, new_scene - )) - - payload["JobInfo"].update(output_data) - payload["PluginInfo"].update(plugin_data) - - self.submit(instance, payload) - - def submit(self, instance, payload): - - context = instance.context - deadline_url = context.data.get("defaultDeadline") - deadline_url = instance.data.get( - "deadlineUrl", deadline_url) - - assert deadline_url, "Requires Deadline Webservice URL" - - plugin = payload["JobInfo"]["Plugin"] - self.log.info("Using Render Plugin : {}".format(plugin)) - - self.log.info("Submitting..") - self.log.debug(json.dumps(payload, indent=4, sort_keys=True)) - - # E.g. http://192.168.0.1:8082/api/jobs - url = "{}/api/jobs".format(deadline_url) - response = requests.post(url, json=payload) - if not response.ok: - raise Exception(response.text) - # Store output dir for unified publisher (expectedFilesequence) - expected_files = instance.data["expectedFiles"] - output_dir = os.path.dirname(expected_files[0]) - instance.data["toBeRenderedOn"] = "deadline" - instance.data["outputDir"] = output_dir - instance.data["deadlineSubmissionJob"] = response.json() - - def rename_render_element(self): - pass - - def _clean_name(self, path): - return os.path.splitext(os.path.basename(path))[0] diff --git a/openpype/modules/deadline/plugins/publish/submit_max_deadline.py b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py new file mode 100644 index 0000000000..3e00f8fd15 --- /dev/null +++ b/openpype/modules/deadline/plugins/publish/submit_max_deadline.py @@ -0,0 +1,217 @@ +import os +import getpass +import copy + +import attr +from openpype.pipeline import legacy_io +from openpype.settings import get_project_settings +from openpype.hosts.max.api.lib import ( + get_current_renderer, + get_multipass_setting +) +from openpype.hosts.max.api.lib_rendersettings import RenderSettings +from openpype_modules.deadline import abstract_submit_deadline +from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo + + +@attr.s +class MaxPluginInfo(object): + SceneFile = attr.ib(default=None) # Input + Version = attr.ib(default=None) # Mandatory for Deadline + SaveFile = attr.ib(default=True) + IgnoreInputs = attr.ib(default=True) + + +class MaxSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline): + + label = "Submit Render to Deadline" + hosts = ["max"] + families = ["maxrender"] + targets = ["local"] + + use_published = True + priority = 50 + tile_priority = 50 + chunk_size = 1 + jobInfo = {} + pluginInfo = {} + group = None + deadline_pool = None + deadline_pool_secondary = None + framePerTask = 1 + + def get_job_info(self): + job_info = DeadlineJobInfo(Plugin="3dsmax") + + # todo: test whether this works for existing production cases + # where custom jobInfo was stored in the project settings + job_info.update(self.jobInfo) + + instance = self._instance + context = instance.context + + # Always use the original work file name for the Job name even when + # rendering is done from the published Work File. The original work + # file name is clearer because it can also have subversion strings, + # etc. which are stripped for the published file. + src_filepath = context.data["currentFile"] + src_filename = os.path.basename(src_filepath) + + job_info.Name = "%s - %s" % (src_filename, instance.name) + job_info.BatchName = src_filename + job_info.Plugin = instance.data["plugin"] + job_info.UserName = context.data.get("deadlineUser", getpass.getuser()) + + # Deadline requires integers in frame range + frames = "{start}-{end}".format( + start=int(instance.data["frameStart"]), + end=int(instance.data["frameEnd"]) + ) + job_info.Frames = frames + + job_info.Pool = instance.data.get("primaryPool") + job_info.SecondaryPool = instance.data.get("secondaryPool") + job_info.ChunkSize = instance.data.get("chunkSize", 1) + job_info.Comment = context.data.get("comment") + job_info.Priority = instance.data.get("priority", self.priority) + job_info.FramesPerTask = instance.data.get("framesPerTask", 1) + + if self.group: + job_info.Group = self.group + + # Add options from RenderGlobals + render_globals = instance.data.get("renderGlobals", {}) + job_info.update(render_globals) + + keys = [ + "FTRACK_API_KEY", + "FTRACK_API_USER", + "FTRACK_SERVER", + "OPENPYPE_SG_USER", + "AVALON_PROJECT", + "AVALON_ASSET", + "AVALON_TASK", + "AVALON_APP_NAME", + "OPENPYPE_DEV", + "OPENPYPE_VERSION", + "IS_TEST" + ] + # Add mongo url if it's enabled + if self._instance.context.data.get("deadlinePassMongoUrl"): + keys.append("OPENPYPE_MONGO") + + environment = dict({key: os.environ[key] for key in keys + if key in os.environ}, **legacy_io.Session) + + for key in keys: + value = environment.get(key) + if not value: + continue + job_info.EnvironmentKeyValue[key] = value + + # to recognize job from PYPE for turning Event On/Off + job_info.EnvironmentKeyValue["OPENPYPE_RENDER_JOB"] = "1" + job_info.EnvironmentKeyValue["OPENPYPE_LOG_NO_COLORS"] = "1" + + # Add list of expected files to job + # --------------------------------- + exp = instance.data.get("expectedFiles") + for filepath in exp: + job_info.OutputDirectory += os.path.dirname(filepath) + job_info.OutputFilename += os.path.basename(filepath) + + return job_info + + def get_plugin_info(self): + instance = self._instance + + plugin_info = MaxPluginInfo( + SceneFile=self.scene_path, + Version=instance.data["maxversion"], + SaveFile = True, + IgnoreInputs = True + ) + + plugin_payload = attr.asdict(plugin_info) + + # Patching with pluginInfo from settings + for key, value in self.pluginInfo.items(): + plugin_payload[key] = value + + return plugin_payload + + def process_submission(self): + + instance = self._instance + context = instance.context + filepath = self.scene_path + + expected_files = instance.data["expectedFiles"] + if not expected_files: + raise RuntimeError("No Render Elements found!") + output_dir = os.path.dirname(expected_files[0]) + instance.data["outputDir"] = output_dir + instance.data["toBeRenderedOn"] = "deadline" + + filename = os.path.basename(filepath) + + payload_data = { + "filename": filename, + "dirname": output_dir + } + + self.log.debug("Submitting 3dsMax render..") + payload = self._use_puhlished_name(payload_data) + job_info, plugin_info = payload + self.submit(self.assemble_payload(job_info, plugin_info)) + + def _use_puhlished_name(self, data): + instance = self._instance + job_info = copy.deepcopy(self.job_info) + plugin_info = copy.deepcopy(self.plugin_info) + plugin_data = {} + project_setting = get_project_settings( + legacy_io.Session["AVALON_PROJECT"] + ) + + multipass = get_multipass_setting(project_setting) + if multipass: + plugin_data["DisableMultipass"] = 0 + else: + plugin_data["DisableMultipass"] = 1 + + expected_files = instance.data.get("expectedFiles") + if not expected_files: + raise RuntimeError("No render elements found") + old_output_dir = os.path.dirname(expected_files[0]) + output_beauty = RenderSettings().get_render_output(instance.name, + old_output_dir) + filepath = self.from_published_scene() + def _clean_name(path): + return os.path.splitext(os.path.basename(path))[0] + new_scene = _clean_name(filepath) + orig_scene = _clean_name(instance.context.data["currentFile"]) + + output_beauty = output_beauty.replace(orig_scene, new_scene) + output_beauty = output_beauty.replace("\\", "/") + plugin_data["RenderOutput"] = output_beauty + + renderer_class = get_current_renderer() + renderer = str(renderer_class).split(":")[0] + if ( + renderer == "ART_Renderer" or + renderer == "Redshift_Renderer" or + renderer == "V_Ray_6_Hotfix_3" or + renderer == "V_Ray_GPU_6_Hotfix_3" or + renderer == "Default_Scanline_Renderer" or + renderer == "Quicksilver_Hardware_Renderer" + ): + render_elem_list = RenderSettings().get_render_element() + for i, element in enumerate(render_elem_list): + element = element.replace(orig_scene, new_scene) + plugin_data["RenderElementOutputFilename%d" % i] = element # noqa + + self.log.debug("plugin data:{}".format(plugin_data)) + plugin_info.update(plugin_data) + + return job_info, plugin_info diff --git a/openpype/settings/defaults/project_settings/deadline.json b/openpype/settings/defaults/project_settings/deadline.json index 7a5903d8e0..7183603c4b 100644 --- a/openpype/settings/defaults/project_settings/deadline.json +++ b/openpype/settings/defaults/project_settings/deadline.json @@ -36,7 +36,7 @@ "scene_patches": [], "strict_error_checking": true }, - "MaxSubmitRenderDeadline": { + "MaxSubmitDeadline": { "enabled": true, "optional": false, "active": true, @@ -122,4 +122,4 @@ } } } -} \ No newline at end of file +} 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 3d1b413d6c..a320dfca4f 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_deadline.json @@ -207,7 +207,7 @@ { "type": "dict", "collapsible": true, - "key": "MaxSubmitRenderDeadline", + "key": "MaxSubmitDeadline", "label": "3dsMax Submit to Deadline", "checkbox_key": "enabled", "children": [