Skip to content

Code Snippets

Roy Nieterau edited this page Jul 26, 2019 · 12 revisions

Interacting with Avalon database

The avalon database uses MongoDB. In Avalon's python api it exposes a thin wrapper around pymongo through avalon.io. Here are some example code snippets of how you could interact with the database.

Search asset by name with regex

Pymongo supports searching by regex and even allows to send a re.compile returned object as the value for a query directly.

import avalon.io as io
import re

# Compile a regex pattern
pattern = re.compile("character_.*")

# Search in avalon database by pattern
for asset in io.find({"name": pattern, "type": "asset"}):
    print(asset)

List all distinct values for a specific key

Using MongoDB it's trivial to list the unique set of values for a specific key using distinct.

import avalon.io as io

# Get all families that are stored in all versions in version["data"]["families"]
families = io.distinct("data.families", {"type": "version"})

Get the latest version of a publish for subset modelDefault for asset hero_x

import avalon.io as io

def get_latest_version(asset_name, subset_name):
    # Get asset and its subset by name
    asset = io.find_one({"name": asset_name, 
                         "type": "asset"})
    subset = io.find_one({"name": subset_name, 
                          "type": "subset", 
                          "parent": asset["_id"]})
    
    # Get last version by using io.find_one() and sorting in reverse by name
    version = io.find_one({"type": "version", 
                           "parent": subset["_id"]},
                          sort=[("name", -1)])
                                    
    return version

version = get_latest_version("hero_x", "modelDefault")

Load a representation with a specific loader through avalon.api

Avalon comes with a Loader tool that makes it easy for artists to load publishes. However, this snippet shows how to do it through code for when you need some automated loading or load assets in bulk, e.g. for a scene builder.

import avalon.api as api

# Get the loader plug-in by its name
name = "AlembicLoader"
loader = next(loader for loader in api.discover(api.Loader) 
                     if loader.__name__ = name)
assert loader, "Loader not found.."

# Assuming you already have the representation id you can load it directly
api.load(loader, representation_id)

List the available Loaders for a representation

You can easily filter the discoverable Loaders to only those that are compatible with a specific representation.

import avalon.api as api

loaders = list(api.discover(api.Loader))
compatible_loaders = api.loaders_from_representation(loaders, representation_id)

Check compatibility of a single loader with a representation

If you have a single Loader and want to check whether it's compatible you can do so using api.loaders_from_representation too, just a pass it [loader].

import avalon.api as api

compatible_loaders = api.loaders_from_representation([loader], representation_id)
is_compatible = any(compatible_loaders)

Avalon does have a function to check compatibility of a single Loader. However this function is not exposed in avalon.api as such it is not enforced to keep its function signature backwards compatible throughout development. It could be stable for use, however the behavior of the functions might change in the future.

import avalon.pipeline

context = avalon.pipeline.get_representation_context(representation_id)
is_compatible = avalon.pipeline.is_compatible_loader(loader, context)

As such, to ensure a stable future, use the avalon.api.

Remove all loaded containers from your current scene

When loading published content into your work file the loaded content can be found in Avalon's Scene Inventory. You can also query these loaded containers through the api.

# Warning: Running this snippet will remove all loaded content from your scene!
import avalon.api as api

host = api.registered_host()
containers = host.ls()

for container in containers:
    api.remove(container)

Note: It is possible for a Loader implemented in a studio configuration to load data unmanaged without a container. In those specific (rare) cases they will not be found with this method. Similarly Avalon's Scene Inventory will also not show them. The loaded content in those cases is "unmanaged".

Publishing

The Avalon pipeline uses Pyblish for publishing. As such you can publish through a nice interface using Pyblish-QML or Pyblish-Lite. However, you can also publish directly through Python. This would also work when running an application in the background, for example if you want to publish on the farm.

For publishing with pyblish easily through python directly it offers some utility functions in pyblish.util.

import pyblish.util
pyblish.util.publish()

However, it's likely you want to check whether your publish succeeded. Note that these utility functions return the Pyblish context:

import pyblish.util
context = pyblish.util.publish()
print(context)

Here's a more verbose example from the Pyblish documentation on reporting:

import pyblish.util
context = pyblish.util.publish()

# Create a printed report of errors that occurred
# See: https://learn.pyblish.com/chapters/16-report-ii.html

header = "{:<10}{:<40} -> {}".format("Success", "Plug-in", "Instance")
result = "{success:<10}{plugin.__name__:<40} -> {instance}"
error = "{:<10}+-- EXCEPTION: {:<70}"

results = list()
for r in context.data["results"]:
  results.append(result.format(**r))
  if r["error"]:
    results.append(error.format("", r["error"]))

report = """
{header}
{line}
{results}
"""
print(report.format(header=header,
                    results="\n".join(results),
                    line="-" * 70))