Merge pull request #2875 from pypeclub/bugfix/OP-2813_AE-rendering-for-single-frame-doesnt-work-in-DL

AfterEffects: Fix rendering for single frame in DL
This commit is contained in:
Petr Kalis 2022-03-18 12:33:08 +01:00 committed by GitHub
commit 1ae7536e9d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 209 additions and 17 deletions

View file

@ -101,7 +101,7 @@ class LoadClip(plugin.NukeLoader):
last += self.handle_end
if not is_sequence:
duration = last - first + 1
duration = last - first
first = 1
last = first + duration
elif "#" not in file:
@ -216,7 +216,7 @@ class LoadClip(plugin.NukeLoader):
last += self.handle_end
if not is_sequence:
duration = last - first + 1
duration = last - first
first = 1
last = first + duration
elif "#" not in file:

View file

@ -10,14 +10,20 @@ def collect_frames(files):
"""
Returns dict of source path and its frame, if from sequence
Uses clique as most precise solution
Uses clique as most precise solution, used when anatomy template that
created files is not known.
Assumption is that frames are separated by '.', negative frames are not
allowed.
Args:
files(list): list of source paths
files(list) or (set with single value): list of source paths
Returns:
(dict): {'/asset/subset_v001.0001.png': '0001', ....}
"""
collections, remainder = clique.assemble(files, minimum_items=1)
patterns = [clique.PATTERNS["frames"]]
collections, remainder = clique.assemble(files, minimum_items=1,
patterns=patterns)
sources_and_frames = {}
if collections:

View file

@ -6,6 +6,7 @@ import pyblish.api
from avalon import api
from openpype.lib import env_value_to_bool
from openpype.lib.delivery import collect_frames
from openpype_modules.deadline import abstract_submit_deadline
from openpype_modules.deadline.abstract_submit_deadline import DeadlineJobInfo
@ -102,24 +103,18 @@ class AfterEffectsSubmitDeadline(
def get_plugin_info(self):
deadline_plugin_info = DeadlinePluginInfo()
context = self._instance.context
script_path = context.data["currentFile"]
render_path = self._instance.data["expectedFiles"][0]
if len(self._instance.data["expectedFiles"]) > 1:
file_name, frame = list(collect_frames([render_path]).items())[0]
if frame:
# replace frame ('000001') with Deadline's required '[#######]'
# expects filename in format project_asset_subset_version.FRAME.ext
render_dir = os.path.dirname(render_path)
file_name = os.path.basename(render_path)
arr = file_name.split('.')
assert len(arr) == 3, \
"Unable to parse frames from {}".format(file_name)
hashed = '[{}]'.format(len(arr[1]) * "#")
render_path = os.path.join(render_dir,
'{}.{}.{}'.format(arr[0], hashed,
arr[2]))
hashed = '[{}]'.format(len(frame) * "#")
file_name = file_name.replace(frame, hashed)
render_path = os.path.join(render_dir, file_name)
deadline_plugin_info.Comp = self._instance.data["comp_name"]
deadline_plugin_info.Version = self._instance.data["app_version"]

View file

@ -606,7 +606,18 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
"fps": instance.get("fps"),
"tags": ["review"]
})
self._solve_families(instance, True)
self._solve_families(instance, True)
already_there = False
for repre in instance.get("representations", []):
# might be added explicitly before by publish_on_farm
already_there = repre.get("files") == rep["files"]
if already_there:
self.log.debug("repre {} already_there".format(repre))
break
if not already_there:
representations.append(rep)
return representations

View file

@ -21,3 +21,27 @@ Specific location could be provided to this command as an argument, either as ab
(eg. `python ${OPENPYPE_ROOT}/start.py start.py runtests ../tests/integration`) will trigger only tests in `integration` folder.
See `${OPENPYPE_ROOT}/cli.py:runtests` for other arguments.
Run in IDE:
-----------
If you prefer to run/debug single file directly in IDE of your choice, you might encounter issues with imports.
It would manifest like `KeyError: 'OPENPYPE_DATABASE_NAME'`. That means you are importing module that depends on OP to be running, eg. all expected variables are set.
In some cases your tests might be so localized, that you don't care about all env vars to be set properly.
In that case you might add this dummy configuration BEFORE any imports in your test file
```
import os
os.environ["AVALON_MONGO"] = "mongodb://localhost:27017"
os.environ["OPENPYPE_MONGO"] = "mongodb://localhost:27017"
os.environ["AVALON_DB"] = "avalon"
os.environ["OPENPYPE_DATABASE_NAME"] = "openpype"
os.environ["AVALON_TIMEOUT"] = '3000'
os.environ["OPENPYPE_DEBUG"] = "3"
os.environ["AVALON_CONFIG"] = "pype"
os.environ["AVALON_ASSET"] = "Asset"
os.environ["AVALON_PROJECT"] = "test_project"
```
(AVALON_ASSET and AVALON_PROJECT values should exist in your environment)
This might be enough to run your test file separately. Do not commit this skeleton though.
Use only when you know what you are doing!

View file

@ -0,0 +1,156 @@
# -*- coding: utf-8 -*-
"""Test suite for delivery functions."""
from openpype.lib.delivery import collect_frames
def test_collect_frames_multi_sequence():
files = ["Asset_renderCompositingMain_v001.0000.png",
"Asset_renderCompositingMain_v001.0001.png",
"Asset_renderCompositingMain_v001.0002.png"]
ret = collect_frames(files)
expected = {
"Asset_renderCompositingMain_v001.0000.png": "0000",
"Asset_renderCompositingMain_v001.0001.png": "0001",
"Asset_renderCompositingMain_v001.0002.png": "0002"
}
print(ret)
assert ret == expected, "Not matching"
def test_collect_frames_multi_sequence_different_format():
files = ["Asset.v001.renderCompositingMain.0000.png",
"Asset.v001.renderCompositingMain.0001.png",
"Asset.v001.renderCompositingMain.0002.png"]
ret = collect_frames(files)
expected = {
"Asset.v001.renderCompositingMain.0000.png": "0000",
"Asset.v001.renderCompositingMain.0001.png": "0001",
"Asset.v001.renderCompositingMain.0002.png": "0002"
}
print(ret)
assert ret == expected, "Not matching"
def test_collect_frames_single_sequence():
files = ["Asset_renderCompositingMain_v001.0000.png"]
ret = collect_frames(files)
expected = {
"Asset_renderCompositingMain_v001.0000.png": "0000"
}
print(ret)
assert ret == expected, "Not matching"
def test_collect_frames_single_sequence_negative():
files = ["Asset_renderCompositingMain_v001.-0000.png"]
ret = collect_frames(files)
expected = {
"Asset_renderCompositingMain_v001.-0000.png": None
}
print(ret)
assert ret == expected, "Not matching"
def test_collect_frames_single_sequence_shot():
files = ["testing_sh010_workfileCompositing_v001.aep"]
ret = collect_frames(files)
expected = {
"testing_sh010_workfileCompositing_v001.aep": None
}
print(ret)
assert ret == expected, "Not matching"
def test_collect_frames_single_sequence_numbers():
files = ["PRJ_204_430_0005_renderLayoutMain_v001.0001.exr"]
ret = collect_frames(files)
expected = {
"PRJ_204_430_0005_renderLayoutMain_v001.0001.exr": "0001"
}
print(ret)
assert ret == expected, "Not matching"
def test_collect_frames_single_sequence_shot_with_frame():
files = ["testing_sh010_workfileCompositing_000_v001.aep"]
ret = collect_frames(files)
expected = {
"testing_sh010_workfileCompositing_000_v001.aep": None
}
print(ret)
assert ret == expected, "Not matching"
def test_collect_frames_single_sequence_full_path():
files = ['C:/test_project/assets/locations/Town/work/compositing\\renders\\aftereffects\\test_project_TestAsset_compositing_v001\\TestAsset_renderCompositingMain_v001.mov'] # noqa: E501
ret = collect_frames(files)
expected = {
'C:/test_project/assets/locations/Town/work/compositing\\renders\\aftereffects\\test_project_TestAsset_compositing_v001\\TestAsset_renderCompositingMain_v001.mov': None # noqa: E501
}
print(ret)
assert ret == expected, "Not matching"
def test_collect_frames_single_sequence_different_format():
files = ["Asset.v001.renderCompositingMain_0000.png"]
ret = collect_frames(files)
expected = {
"Asset.v001.renderCompositingMain_0000.png": None
}
print(ret)
assert ret == expected, "Not matching"
def test_collect_frames_single_sequence_withhout_version():
files = ["pngv001.renderCompositingMain_0000.png"]
ret = collect_frames(files)
expected = {
"pngv001.renderCompositingMain_0000.png": None
}
print(ret)
assert ret == expected, "Not matching"
def test_collect_frames_single_sequence_as_dict():
files = {"Asset_renderCompositingMain_v001.0000.png"}
ret = collect_frames(files)
expected = {
"Asset_renderCompositingMain_v001.0000.png": "0000"
}
print(ret)
assert ret == expected, "Not matching"
def test_collect_frames_single_file():
files = {"Asset_renderCompositingMain_v001.png"}
ret = collect_frames(files)
expected = {
"Asset_renderCompositingMain_v001.png": None
}
print(ret)
assert ret == expected, "Not matching"