Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Commit

Permalink
changes from PR #903
Browse files Browse the repository at this point in the history
  • Loading branch information
iLLiCiTiT committed Jan 21, 2021
1 parent 547f252 commit e1f7083
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 45 deletions.
140 changes: 98 additions & 42 deletions pype/hosts/tvpaint/plugins/load/load_reference_image.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import collections
from avalon.pipeline import get_representation_context
from avalon.vendor import qargparse
from avalon.tvpaint import lib, pipeline
Expand All @@ -15,7 +16,7 @@ class LoadImage(pipeline.Loader):
color = "white"

import_script = (
"filepath = \"{}\"\n"
"filepath = '\"'\"{}\"'\"'\n"
"layer_name = \"{}\"\n"
"tv_loadsequence filepath {}PARSE layer_id\n"
"tv_layerrename layer_id layer_name"
Expand Down Expand Up @@ -92,30 +93,55 @@ def load(self, context, name, namespace, options):
"Loading probably failed during execution of george script."
)

layer_ids = [loaded_layer["layer_id"]]
layer_names = [loaded_layer["name"]]
namespace = namespace or layer_name
return pipeline.containerise(
name=name,
namespace=namespace,
layer_ids=layer_ids,
members=layer_names,
context=context,
loader=self.__class__.__name__
)

def _remove_layers(self, layer_ids, layers=None):
if not layer_ids:
self.log.warning("Got empty layer ids list.")
def _remove_layers(self, layer_names=None, layer_ids=None, layers=None):
if not layer_names and not layer_ids:
self.log.warning("Got empty layer names list.")
return

if layers is None:
layers = lib.layers_data()

available_ids = set(layer["layer_id"] for layer in layers)

if layer_ids is None:
# Backwards compatibility (layer ids were stored instead of names)
layer_names_are_ids = True
for layer_name in layer_names:
if (
not isinstance(layer_name, int)
and not layer_name.isnumeric()
):
layer_names_are_ids = False
break

if layer_names_are_ids:
layer_ids = layer_names

layer_ids_to_remove = []
if layer_ids is not None:
for layer_id in layer_ids:
if layer_id in available_ids:
layer_ids_to_remove.append(layer_id)

for layer_id in layer_ids:
if layer_id in available_ids:
layer_ids_to_remove.append(layer_id)
else:
layers_by_name = collections.defaultdict(list)
for layer in layers:
layers_by_name[layer["name"]].append(layer)

for layer_name in layer_names:
layers = layers_by_name[layer_name]
if len(layers) == 1:
layer_ids_to_remove.append(layers[0]["layer_id"])

if not layer_ids_to_remove:
self.log.warning("No layers to delete.")
Expand All @@ -128,16 +154,19 @@ def _remove_layers(self, layer_ids, layers=None):
george_script = "\n".join(george_script_lines)
lib.execute_george_through_file(george_script)

def remove(self, container):
layer_ids = self.layer_ids_from_container(container)
self.log.warning("Layers to delete {}".format(layer_ids))
self._remove_layers(layer_ids)

def _remove_container(self, container, members=None):
if not container:
return
representation = container["representation"]
members = self.get_members_from_container(container)
current_containers = pipeline.ls()
pop_idx = None
for idx, cur_con in enumerate(current_containers):
cur_con_layer_ids = self.layer_ids_from_container(cur_con)
if cur_con_layer_ids == layer_ids:
cur_members = self.get_members_from_container(cur_con)
if (
cur_members == members
and cur_con["representation"] == representation
):
pop_idx = idx
break

Expand All @@ -154,6 +183,12 @@ def remove(self, container):
pipeline.SECTION_NAME_CONTAINERS, current_containers
)

def remove(self, container):
members = self.get_members_from_container(container)
self.log.warning("Layers to delete {}".format(members))
self._remove_layers(members)
self._remove_container(container)

def switch(self, container, representation):
self.update(container, representation)

Expand All @@ -166,39 +201,41 @@ def update(self, container, representation):
"""
# Create new containers first
context = get_representation_context(representation)
# Change `fname` to new representation
self.fname = self.filepath_from_context(context)

name = container["name"]
namespace = container["namespace"]
new_container = self.load(context, name, namespace, {})
new_layer_ids = self.layer_ids_from_container(new_container)

# Get layer ids from previous container
old_layer_ids = self.layer_ids_from_container(container)
old_layer_names = self.get_members_from_container(container)

layers = lib.layers_data()
layers_by_id = {
layer["layer_id"]: layer
for layer in layers
}
# Backwards compatibility (layer ids were stored instead of names)
old_layers_are_ids = True
for name in old_layer_names:
if isinstance(name, int) or name.isnumeric():
continue
old_layers_are_ids = False
break

old_layers = []
new_layers = []
for layer_id in old_layer_ids:
layer = layers_by_id.get(layer_id)
if layer:
old_layers.append(layer)

for layer_id in new_layer_ids:
layer = layers_by_id.get(layer_id)
if layer:
new_layers.append(layer)
layers = lib.layers_data()
previous_layer_ids = set(layer["layer_id"] for layer in layers)
if old_layers_are_ids:
for layer in layers:
if layer["layer_id"] in old_layer_names:
old_layers.append(layer)
else:
layers_by_name = collections.defaultdict(list)
for layer in layers:
layers_by_name[layer["name"]].append(layer)

for layer_name in old_layer_names:
layers = layers_by_name[layer_name]
if len(layers) == 1:
old_layers.append(layers[0])

# Prepare few data
new_start_position = None
new_group_id = None
layer_ids_to_remove = set()
for layer in old_layers:
layer_ids_to_remove.add(layer["layer_id"])
position = layer["position"]
group_id = layer["group_id"]
if new_start_position is None:
Expand All @@ -213,6 +250,28 @@ def update(self, container, representation):
elif new_group_id != group_id:
new_group_id = -1

# Remove old container
self._remove_container(container)
# Remove old layers
self._remove_layers(layer_ids=layer_ids_to_remove)

# Change `fname` to new representation
self.fname = self.filepath_from_context(context)

name = container["name"]
namespace = container["namespace"]
new_container = self.load(context, name, namespace, {})
new_layer_names = self.get_members_from_container(new_container)

layers = lib.layers_data()

new_layers = []
for layer in layers:
if layer["layer_id"] in previous_layer_ids:
continue
if layer["name"] in new_layer_names:
new_layers.append(layer)

george_script_lines = []
# Group new layers to same group as previous container layers had
# - all old layers must be under same group
Expand Down Expand Up @@ -246,6 +305,3 @@ def update(self, container, representation):
if george_script_lines:
george_script = "\n".join(george_script_lines)
lib.execute_george_through_file(george_script)

# Remove old container
self.remove(container)
27 changes: 25 additions & 2 deletions pype/hosts/tvpaint/plugins/publish/collect_instances.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,31 @@ def create_render_pass_instance(self, context, instance_data):
for layer in layers_data
}

# QUESTION add backwards compatibility for `layer_ids`?
layer_names = instance_data["layer_names"]
if "layer_names" in instance_data:
layer_names = instance_data["layer_names"]
else:
# Backwards compatibility
# - not 100% working as it was found out that layer ids can't be
# used as unified identifier across multiple workstations
layers_by_id = {
layer["id"]: layer
for layer in layers_data
}
layer_ids = instance_data["layer_ids"]
layer_names = []
for layer_id in layer_ids:
layer = layers_by_id.get(layer_id)
if layer:
layer_names.append(layer["name"])

if not layer_names:
raise ValueError((
"Metadata contain old way of storing layers information."
" It is not possible to identify layers to publish with"
" these data. Please remove Render Pass instances with"
" Subset manager and use Creator tool to recreate them."
))

render_pass_layers = []
for layer_name in layer_names:
layer = layers_by_name.get(layer_name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def process(self, context):
layers_by_name[layer_name] = []
layers_by_name[layer_name].append(layer)
context.data["layersData"] = layers_data
context.data["layersByName"] = layers_data
context.data["layersByName"] = layers_by_name

self.log.debug(
"Layers data:\"{}".format(json.dumps(layers_data, indent=4))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import pyblish.api


class ValidateLayersGroup(pyblish.api.InstancePlugin):
"""Validate layer names for publishing are unique for whole workfile."""

label = "Validate Duplicated Layers Names"
order = pyblish.api.ValidatorOrder
families = ["renderPass"]

def process(self, instance):
# Prepare layers
layers_by_name = instance.context.data["layersByName"]

# Layers ids of an instance
layer_names = instance.data["layer_names"]

# Check if all layers from render pass are in right group
duplicated_layer_names = []
for layer_name in layer_names:
layers = layers_by_name.get(layer_name)
if len(layers) > 1:
duplicated_layer_names.append(layer_name)

# Everything is OK and skip exception
if not duplicated_layer_names:
return

layers_msg = ", ".join([
"\"{}\"".format(layer_name)
for layer_name in duplicated_layer_names
])

# Raise an error
raise AssertionError(
(
"Layers have duplicated names for instance {}."
# Description what's wrong
" There are layers with same name and one of them is marked"
" for publishing so it is not possible to know which should"
" be published. Please look for layers with names: {}"
).format(instance.data["label"], layers_msg)
)
42 changes: 42 additions & 0 deletions pype/hosts/tvpaint/plugins/publish/validate_missing_layer_names.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import pyblish.api


class ValidateMissingLayers(pyblish.api.InstancePlugin):
"""Validate existence of renderPass layers."""

label = "Validate Missing Layers Names"
order = pyblish.api.ValidatorOrder
families = ["renderPass"]

def process(self, instance):
# Prepare layers
layers_by_name = instance.context.data["layersByName"]

# Layers ids of an instance
layer_names = instance.data["layer_names"]

# Check if all layers from render pass are in right group
missing_layer_names = []
for layer_name in layer_names:
layers = layers_by_name.get(layer_name)
if not layers:
missing_layer_names.append(layer_name)

# Everything is OK and skip exception
if not missing_layer_names:
return

layers_msg = ", ".join([
"\"{}\"".format(layer_name)
for layer_name in missing_layer_names
])

# Raise an error
raise AssertionError(
(
"Layers were not found by name for instance \"{}\"."
# Description what's wrong
" Layer names marked for publishing are not available"
" in layers list. Missing layer names: {}"
).format(instance.data["label"], layers_msg)
)

0 comments on commit e1f7083

Please sign in to comment.