From 618b4b0c6d7b4cd7af858558de0463134d39634c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Mon, 27 Nov 2023 12:22:11 +0100 Subject: [PATCH 1/9] :art: inject submitter environment to the royal render job --- openpype/modules/royalrender/lib.py | 88 +++++++++++++++++-- .../publish/create_maya_royalrender_job.py | 3 +- .../publish/create_publish_royalrender_job.py | 3 + openpype/modules/royalrender/rr_job.py | 4 +- 4 files changed, 86 insertions(+), 12 deletions(-) diff --git a/openpype/modules/royalrender/lib.py b/openpype/modules/royalrender/lib.py index 4708d25eed..9c4221d9cd 100644 --- a/openpype/modules/royalrender/lib.py +++ b/openpype/modules/royalrender/lib.py @@ -1,23 +1,28 @@ # -*- coding: utf-8 -*- """Submitting render job to RoyalRender.""" import os -import re +import json import platform +import re +import tempfile +import uuid from datetime import datetime import pyblish.api -from openpype.tests.lib import is_in_tests -from openpype.pipeline.publish.lib import get_published_workfile_instance -from openpype.pipeline.publish import KnownPublishError + +from openpype.lib import BoolDef, NumberDef, is_running_from_build +from openpype.lib.execute import run_openpype_process from openpype.modules.royalrender.api import Api as rrApi from openpype.modules.royalrender.rr_job import ( - RRJob, CustomAttribute, get_rr_platform) -from openpype.lib import ( - is_running_from_build, - BoolDef, - NumberDef, + CustomAttribute, + RRJob, + RREnvList, + get_rr_platform, ) from openpype.pipeline import OpenPypePyblishPluginMixin +from openpype.pipeline.publish import KnownPublishError +from openpype.pipeline.publish.lib import get_published_workfile_instance +from openpype.tests.lib import is_in_tests class BaseCreateRoyalRenderJob(pyblish.api.InstancePlugin, @@ -302,3 +307,68 @@ class BaseCreateRoyalRenderJob(pyblish.api.InstancePlugin, path = path.replace(first_frame, "#" * padding) return path + + def inject_environment(self, instance, job): + # type: (pyblish.api.Instance, RRJob) -> RRJob + """Inject environment variables for RR submission. + + This function mimics the behaviour of the Deadline + integration. It is just temporary solution until proper + runtime environment injection is implemented in RR. + + Args: + instance (pyblish.api.Instance): Publishing instance + job (RRJob): RRJob instance to be injected. + + Returns: + RRJob: Injected RRJob instance. + + Throws: + RuntimeError: If any of the required env vars is missing. + + """ + + temp_file_name = "{}_{}.json".format( + datetime.utcnow().strftime('%Y%m%d%H%M%S%f'), + str(uuid.uuid1()) + ) + + export_url = os.path.join(tempfile.gettempdir(), temp_file_name) + print(">>> Temporary path: {}".format(export_url)) + + args = [ + "--headless", + "extractenvironments", + export_url + ] + + anatomy_data = instance.context.data["anatomyData"] + + add_kwargs = { + "project": anatomy_data["project"]["name"], + "asset": instance.context.data["asset"], + "task": anatomy_data["task"]["name"], + "app": instance.context.data.get("appName"), + "envgroup": "farm" + } + + if os.getenv('IS_TEST'): + args.append("--automatic-tests") + + if not all(add_kwargs.values()): + raise RuntimeError(( + "Missing required env vars: AVALON_PROJECT, AVALON_ASSET," + " AVALON_TASK, AVALON_APP_NAME" + )) + + for key, value in add_kwargs.items(): + args.extend([f"--{key}", value]) + self.log.debug("Executing: {}".format(" ".join(args))) + run_openpype_process(*args, logger=self.log) + + self.log.debug("Loading file ...") + with open(export_url) as fp: + contents = json.load(fp) + + job.rrEnvList = RREnvList(contents).serialize() + return job diff --git a/openpype/modules/royalrender/plugins/publish/create_maya_royalrender_job.py b/openpype/modules/royalrender/plugins/publish/create_maya_royalrender_job.py index 22d910b7cd..775a2964fd 100644 --- a/openpype/modules/royalrender/plugins/publish/create_maya_royalrender_job.py +++ b/openpype/modules/royalrender/plugins/publish/create_maya_royalrender_job.py @@ -2,7 +2,7 @@ """Submitting render job to RoyalRender.""" import os -from maya.OpenMaya import MGlobal +from maya.OpenMaya import MGlobal # noqa: F401 from openpype.modules.royalrender import lib from openpype.pipeline.farm.tools import iter_expected_files @@ -38,5 +38,6 @@ class CreateMayaRoyalRenderJob(lib.BaseCreateRoyalRenderJob): job = self.get_job(instance, self.scene_path, first_file_path, layer_name) job = self.update_job_with_host_specific(instance, job) + job = self.inject_environment(instance, job) instance.data["rrJobs"].append(job) diff --git a/openpype/modules/royalrender/plugins/publish/create_publish_royalrender_job.py b/openpype/modules/royalrender/plugins/publish/create_publish_royalrender_job.py index e13bf97e54..9be5d300df 100644 --- a/openpype/modules/royalrender/plugins/publish/create_publish_royalrender_job.py +++ b/openpype/modules/royalrender/plugins/publish/create_publish_royalrender_job.py @@ -205,6 +205,9 @@ class CreatePublishRoyalRenderJob(pyblish.api.InstancePlugin, jobs_pre_ids = [] for job in instance.data["rrJobs"]: # type: RRJob if job.rrEnvList: + if len(job.rrEnvList) > 2000: + self.log.warning(("Job environment is too long " + f"{len(job.rrEnvList)} > 2000")) job_environ.update( dict(RREnvList.parse(job.rrEnvList)) ) diff --git a/openpype/modules/royalrender/rr_job.py b/openpype/modules/royalrender/rr_job.py index b85ac592f8..62a82d45e8 100644 --- a/openpype/modules/royalrender/rr_job.py +++ b/openpype/modules/royalrender/rr_job.py @@ -32,7 +32,7 @@ class RREnvList(dict): """Parse rrEnvList string and return it as RREnvList object.""" out = RREnvList() for var in data.split("~~~"): - k, v = var.split("=") + k, v = var.split("=", maxsplit=1) out[k] = v return out @@ -172,7 +172,7 @@ class RRJob(object): # Environment # only used in RR 8.3 and newer - rrEnvList = attr.ib(default=None) # type: str + rrEnvList = attr.ib(default=None, type=str) # type: str class SubmitterParameter: From fbc8021b45a3456fe37f402b7c9918eab02ced66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Mon, 27 Nov 2023 12:54:28 +0100 Subject: [PATCH 2/9] :bug: prevent passing all environments --- openpype/pype_commands.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/pype_commands.py b/openpype/pype_commands.py index b5828d3dfe..b6535e0835 100644 --- a/openpype/pype_commands.py +++ b/openpype/pype_commands.py @@ -186,6 +186,7 @@ class PypeCommands: app, env_group=env_group, launch_type=LaunchTypes.farm_render, + env={} ) else: env = os.environ.copy() From 425cbd2ac0524f45ef0a7c7196f8455d9d010d51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Mon, 27 Nov 2023 13:12:07 +0100 Subject: [PATCH 3/9] :dog: fix hound --- .../plugins/publish/create_publish_royalrender_job.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/modules/royalrender/plugins/publish/create_publish_royalrender_job.py b/openpype/modules/royalrender/plugins/publish/create_publish_royalrender_job.py index 9be5d300df..d4af1c2aee 100644 --- a/openpype/modules/royalrender/plugins/publish/create_publish_royalrender_job.py +++ b/openpype/modules/royalrender/plugins/publish/create_publish_royalrender_job.py @@ -206,8 +206,8 @@ class CreatePublishRoyalRenderJob(pyblish.api.InstancePlugin, for job in instance.data["rrJobs"]: # type: RRJob if job.rrEnvList: if len(job.rrEnvList) > 2000: - self.log.warning(("Job environment is too long " - f"{len(job.rrEnvList)} > 2000")) + self.log.warning(("Job environment is too long " + f"{len(job.rrEnvList)} > 2000")) job_environ.update( dict(RREnvList.parse(job.rrEnvList)) ) From 5175cdfe8366a4a48ca6e69ab5b388a8cd540490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Mon, 27 Nov 2023 13:49:15 +0100 Subject: [PATCH 4/9] :sparkles: inject env to nuke jobs --- .../royalrender/plugins/publish/create_nuke_royalrender_job.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/modules/royalrender/plugins/publish/create_nuke_royalrender_job.py b/openpype/modules/royalrender/plugins/publish/create_nuke_royalrender_job.py index 71daa6edf8..4f589e56f8 100644 --- a/openpype/modules/royalrender/plugins/publish/create_nuke_royalrender_job.py +++ b/openpype/modules/royalrender/plugins/publish/create_nuke_royalrender_job.py @@ -25,6 +25,7 @@ class CreateNukeRoyalRenderJob(lib.BaseCreateRoyalRenderJob): jobs = self.create_jobs(instance) for job in jobs: job = self.update_job_with_host_specific(instance, job) + job = self.inject_environment(instance, job) instance.data["rrJobs"].append(job) From 463a7fb323f7f81d266ac354579775b7502c4f12 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Mon, 4 Dec 2023 15:13:23 +0000 Subject: [PATCH 5/9] Skip Arnold license for test rendering. (#5984) --- .../input/workfile/test_project_test_asset_test_task_v001.ma | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration/hosts/maya/test_deadline_publish_in_maya/input/workfile/test_project_test_asset_test_task_v001.ma b/tests/integration/hosts/maya/test_deadline_publish_in_maya/input/workfile/test_project_test_asset_test_task_v001.ma index c476a78086..2e882a5baa 100644 --- a/tests/integration/hosts/maya/test_deadline_publish_in_maya/input/workfile/test_project_test_asset_test_task_v001.ma +++ b/tests/integration/hosts/maya/test_deadline_publish_in_maya/input/workfile/test_project_test_asset_test_task_v001.ma @@ -236,6 +236,7 @@ createNode polyDisc -n "polyDisc1"; rename -uid "9ED8A7BD-4FFD-6107-4322-35ACD1D3AC42"; createNode aiOptions -s -n "defaultArnoldRenderOptions"; rename -uid "31A81965-48A6-B90D-503D-2FA162B7C982"; + setAttr ".skip_license_check" yes; createNode aiAOVFilter -s -n "defaultArnoldFilter"; rename -uid "77A2BCB1-4613-905E-080E-B997FD5E1C6F"; setAttr ".ai_translator" -type "string" "gaussian"; From 71badb50ccaab5c4e1e3801e8268721c0ae7f133 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Mon, 4 Dec 2023 15:14:59 +0000 Subject: [PATCH 6/9] Do not persist data by default. (#5987) --- tests/integration/hosts/maya/test_deadline_publish_in_maya.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/hosts/maya/test_deadline_publish_in_maya.py b/tests/integration/hosts/maya/test_deadline_publish_in_maya.py index c2ef342600..7d2b409db3 100644 --- a/tests/integration/hosts/maya/test_deadline_publish_in_maya.py +++ b/tests/integration/hosts/maya/test_deadline_publish_in_maya.py @@ -21,7 +21,7 @@ class TestDeadlinePublishInMaya(MayaDeadlinePublishTestClass): {OPENPYPE_ROOT}/.venv/Scripts/python.exe {OPENPYPE_ROOT}/start.py runtests ../tests/integration/hosts/maya # noqa: E501 """ - PERSIST = True + PERSIST = False TEST_FILES = [ ("test_deadline_publish_in_maya", "", "") From 1721563a5f0ef733731275a236cb5ac3fc34a9f6 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 4 Dec 2023 18:28:08 +0100 Subject: [PATCH 7/9] Photoshop: Fix removed unsupported Path (#5996) * Fix removed unsupported Path Path is not json serializable by default, it is not necessary, better model reused. * Fix wrong key Must be 'path', not 'template_path' as workfile builder expects the former one. --- .../server/settings/workfile_builder.py | 28 ++++++------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/server_addon/photoshop/server/settings/workfile_builder.py b/server_addon/photoshop/server/settings/workfile_builder.py index ec2ee136ad..68db05270d 100644 --- a/server_addon/photoshop/server/settings/workfile_builder.py +++ b/server_addon/photoshop/server/settings/workfile_builder.py @@ -1,31 +1,18 @@ from pydantic import Field -from pathlib import Path -from ayon_server.settings import BaseSettingsModel - - -class PathsTemplate(BaseSettingsModel): - windows: Path = Field( - '', - title="Windows" - ) - darwin: Path = Field( - '', - title="MacOS" - ) - linux: Path = Field( - '', - title="Linux" - ) +from ayon_server.settings import BaseSettingsModel, MultiplatformPathModel class CustomBuilderTemplate(BaseSettingsModel): + _layout = "expanded" task_types: list[str] = Field( default_factory=list, title="Task types", ) - template_path: PathsTemplate = Field( - default_factory=PathsTemplate + + path: MultiplatformPathModel = Field( + default_factory=MultiplatformPathModel, + title="Template path" ) @@ -37,5 +24,6 @@ class WorkfileBuilderPlugin(BaseSettingsModel): ) custom_templates: list[CustomBuilderTemplate] = Field( - default_factory=CustomBuilderTemplate + default_factory=CustomBuilderTemplate, + title="Template profiles" ) From fe132f1d6aad13e15ca848d8a0a396189eaaa3c8 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 5 Dec 2023 11:27:04 +0100 Subject: [PATCH 8/9] AYON: Prepare functions for newer ayon-python-api (#5997) * use kwargs to define filters in ayon api * use new variable for version entities * fix kwarg for product_ids --- openpype/client/server/entities.py | 34 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/openpype/client/server/entities.py b/openpype/client/server/entities.py index 75e58703be..75b5dc2cdd 100644 --- a/openpype/client/server/entities.py +++ b/openpype/client/server/entities.py @@ -80,8 +80,8 @@ def _get_subsets( for subset in con.get_products( project_name, - subset_ids, - subset_names, + product_ids=subset_ids, + product_names=subset_names, folder_ids=folder_ids, names_by_folder_ids=names_by_folder_ids, active=active, @@ -113,23 +113,23 @@ def _get_versions( queried_versions = con.get_versions( project_name, - version_ids, - subset_ids, - versions, - hero, - standard, - latest, + version_ids=version_ids, + product_ids=subset_ids, + versions=versions, + hero=hero, + standard=standard, + latest=latest, active=active, fields=fields ) - versions = [] + version_entities = [] hero_versions = [] for version in queried_versions: if version["version"] < 0: hero_versions.append(version) else: - versions.append(convert_v4_version_to_v3(version)) + version_entities.append(convert_v4_version_to_v3(version)) if hero_versions: subset_ids = set() @@ -159,9 +159,9 @@ def _get_versions( break conv_hero = convert_v4_version_to_v3(hero_version) conv_hero["version_id"] = version_id - versions.append(conv_hero) + version_entities.append(conv_hero) - return versions + return version_entities def get_asset_by_id(project_name, asset_id, fields=None): @@ -539,11 +539,11 @@ def get_representations( representations = con.get_representations( project_name, - representation_ids, - representation_names, - version_ids, - names_by_version_ids, - active, + representation_ids=representation_ids, + representation_names=representation_names, + version_ids=version_ids, + names_by_version_ids=names_by_version_ids, + active=active, fields=fields ) for representation in representations: From a557b8b5e3fcd8d078c24fe981a054af49e99207 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 5 Dec 2023 13:04:32 +0100 Subject: [PATCH 9/9] Wrap: new integration (#5823) * Added Wrap to applications * Added icon * Added wrap to template pre hooks Needed to copy template as new workfile. Needed to open Wrap with workfile. --- openpype/hooks/pre_add_last_workfile_arg.py | 1 + openpype/hooks/pre_copy_template_workfile.py | 3 +- openpype/resources/app_icons/wrap.png | Bin 0 -> 1044 bytes .../applications/server/applications.json | 26 ++++++++++++++++++ server_addon/applications/server/settings.py | 2 ++ 5 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 openpype/resources/app_icons/wrap.png diff --git a/openpype/hooks/pre_add_last_workfile_arg.py b/openpype/hooks/pre_add_last_workfile_arg.py index 1418bc210b..6e255ae82a 100644 --- a/openpype/hooks/pre_add_last_workfile_arg.py +++ b/openpype/hooks/pre_add_last_workfile_arg.py @@ -27,6 +27,7 @@ class AddLastWorkfileToLaunchArgs(PreLaunchHook): "tvpaint", "substancepainter", "aftereffects", + "wrap" } launch_types = {LaunchTypes.local} diff --git a/openpype/hooks/pre_copy_template_workfile.py b/openpype/hooks/pre_copy_template_workfile.py index 2203ff4396..4d91d83c95 100644 --- a/openpype/hooks/pre_copy_template_workfile.py +++ b/openpype/hooks/pre_copy_template_workfile.py @@ -19,7 +19,8 @@ class CopyTemplateWorkfile(PreLaunchHook): # Before `AddLastWorkfileToLaunchArgs` order = 0 - app_groups = {"blender", "photoshop", "tvpaint", "aftereffects"} + app_groups = {"blender", "photoshop", "tvpaint", "aftereffects", + "wrap"} launch_types = {LaunchTypes.local} def execute(self): diff --git a/openpype/resources/app_icons/wrap.png b/openpype/resources/app_icons/wrap.png new file mode 100644 index 0000000000000000000000000000000000000000..34ae1d68ed9de874a612d94bf69804de2af01eea GIT binary patch literal 1044 zcmV+v1nc{WP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1F1R6 zy`}G^1FGW7AMy2h&h=gpfo?ynGnqH}=C=7h=lPuToO7Q00sf;$fc<_y>~?$Fq=9WV z8zf0eo8E)drgsaxP0|TvNO~duy?W4UPxaTvWYGVul=|}v1oolVG){6v2megSYBTaE^{s;uk`(2u2!cz`G=Ex-!dg}?pv5~rg8j~2 zIB9aj4`mFxCvdQ~9vL)#Q!o$y{`6T5%(~Ij2gzVYR(>ID*KgsTF9bR9MDyj?A{v{T zu|+bV`fv^UY2plJ@gz#D%A`_)t>qQ)$CtFk;rT`678YZBX*uqW-pBB?3~zJ+k=K4S z`5e7{12E+j;N;o!aCp38#ZD@B=jCfKXIfH&Sp`K!xZ@ZRd&r67l=yJnF&t_C-2rVf-%Qfb~m*3Rk!p&X`GnDk__!JJ()~wFW+7N8c%tC8h2jZ{6F;egEPS|?- zX|<2wpq0310|+cEYv6~$IIi9vK%dJkO3YxcPBB$!b#B&%U`eOL=ha_hF1Da04*c~5 zLzA>x0&~*Ady^RR1`wfYu+MJ~Rlzx>_zb^6<goJcipBq*5y@Zfb53O=fNGO~Ki@`S{6pu20wc8I?*2dC%BLzNxMJ5{42?bzhl`Vj=@fhBqUgHbgB>MS5mVRLEKa=&mZ<`6 zuOBtXTi(j2Dka#GlMnl?KDwt$m*NBD4bP+bbUO@Y<N literal 0 HcmV?d00001 diff --git a/server_addon/applications/server/applications.json b/server_addon/applications/server/applications.json index f846b04215..825f50276a 100644 --- a/server_addon/applications/server/applications.json +++ b/server_addon/applications/server/applications.json @@ -1158,6 +1158,32 @@ } ] }, + "wrap": { + "enabled": true, + "label": "Wrap", + "icon": "{}/app_icons/wrap.png", + "host_name": "wrap", + "environment": "{\n \n}", + "variants": [ + { + "name": "2023", + "use_python_2": false, + "executables": { + "windows": [ + "c:\\Program Files\\Faceform\\Wrap 2023.10.2\\Wrap.exe" + ], + "darwin": [], + "linux": [] + }, + "arguments": { + "windows": [], + "darwin": [], + "linux": [] + }, + "environment": "{\n \n}" + } + ] + }, "additional_apps": [] } } diff --git a/server_addon/applications/server/settings.py b/server_addon/applications/server/settings.py index 981d56c30f..224f999564 100644 --- a/server_addon/applications/server/settings.py +++ b/server_addon/applications/server/settings.py @@ -168,6 +168,8 @@ class ApplicationsSettings(BaseSettingsModel): default_factory=AppGroupWithPython, title="Substance Painter") unreal: AppGroup = Field( default_factory=AppGroupWithPython, title="Unreal Editor") + wrap: AppGroup = Field( + default_factory=AppGroupWithPython, title="Wrap") additional_apps: list[AdditionalAppGroup] = Field( default_factory=list, title="Additional Applications")