Correct usage of instance/family/data

Hi,

I am still in the process of learning Pyblish, now I am turning my head to our lookdev department.
I want to validate:

  • ShadingEngines
  • Meshes
  • Textures

So how should I collect them?
According to CVEI documentation, only Collectors should read data from the scene. So I should create instances for them and store the data in it.
So something like

instance = create_instance("spiderman_meshes", family="lookdev.meshes")
instance[:] = meshes
# ... same for textures and SEs

and match the family for each validator.
But as I understand, instances are basically the data that I want to export, so it should be one instance per asset.

instance = create_instance("spiderman", family="lookdev")
instance.data["meshes"] = meshes
instance.data["textures"] = textures
instance.data["shadingEngines"] = shading_engines

and then getting the appropriate data inside validators. But in the aforementioned documentation:

No plug-in depend on another plug-in (2 points)

and this makes them heavily depend on the LookdevCollector plug-in.
So which is the correct approach, or am I misunderstanding something?

Hey @asztalosdani, welcome to the forums!

You’re right, that’s ambiguous. The four stages of CVEI have a natural relationship that you are encouraged to exploit; in this case, it’s the relationship that collection collects information for you to use in subsequent stages. What these 2 points are awarded for is when plug-ins that go beyond this natural relationship become dependent on each other.

For example.

from pyblish import api

class CollectTransforms(api.ContextPlugin):
  order = api.CollectorOrder 

  def process(self, context):
    from maya import cmds

    for assembly in cmds.ls(assemblies=True):
      context.create_instance(assembly)


class CollectAttributes(api.ContextPlugin):
  order = api.CollectorOrder

  def process(self, context):
    from maya import cmds

    for instance in context:
      instance.data["visibility"] = cmds.getAttr(
        instance.data["name"] + ".visible")

In here you’ve made CollectAttributes dependent on CollectTransforms in that CollectTransforms is assumed to run first. The way you can guarantee this, is by tweaking the order variable.

class CollectAttributes(api.ContextPlugin):
  order = api.CollectorOrder + 0.1

And viola, a dependency. Sometimes these are unavoidable (and sometimes even OK), but they are generally discouraged.

Does this answer your question?

Thanks, @marcus!
This clarifies the plug-in dependency (maybe the documentation should be updated too).
So are you suggesting that my second solution is more appropriate?

BTW, I have a third one, which I like more:
In the collector I can collect all nodes that are used and taking part in the lookdev process, shaders, meshes, textures, etc.

instance = create_instance("spiderman", family="lookdev")
instance.data["nodes"] = nodes # all nodes used by the shaders

And then in the validators I can get the ones it is looking for:

for shading_engine in pm.ls(instance.data['nodes'], type='shadingEngine'):
    # validate it

For nodes, I’d recommend adding them to the instance itself, like in your first example.

instance[:] = meshes

Then you can do…

for shading_engine in pm.ls(instance, type='shadingEngine'):

As the Instance object is subclassed from a typical Python list type. There isn’t nothing in Pyblish that assumes that you do, so either approach that makes the most sense to you is fine.

Conceptually, the instance is considered “the inverse of a file” as in, it should contain what you would get if you were to import the resulting published file. But also here it’s just a guideline and is mainly intended to simplify the vocabulary during conversations about publishing, such as this one.

Yes, you are right! Thanks, I think this solves my problem.

1 Like