User Guide

This guide is for TDs and technical artists who want to use Spil.

The guide to modify spil is here developer guide.
See also the glossay.

Introduction to the Sid

The “Sid” - for “Scene Identifier” - is a human-readable, hierarchical, path-like unique identifier for every entity or file of a CG production pipeline.
An intuitive API is built around this identifier, including glob-like query, CRUD data access and path resolving.

In practice, it is an immutable string, looking like a path, and representing hierarchical data.

Examples (for a movie called “hamlet”):

"hamlet/s/sq030/sh0100/anim"
"hamlet/s/sq030/sh0100/render"
"hamlet/s/sq030/sh0100"
"hamlet/a/char/ophelia/model/v001/w/ma"
"hamlet/a/char"
"hamlet"

At creation time, the string is “resolved”, matched against configurated templates. (Resolving done by resolva)

If the resolve succeeds, it defines the Sids type, and store its data in a dictionary. Finally, a Sid contains 3 values.

  1. A string This is the bare minimum for a Sid to exist. By default it is an empty string.

  2. A dictionary If the string matches a defined pattern, the fields dictionary is filled.

  3. A type The matching pattern gives the Sid its type. The type is of form basetype__keytype.

Examples:

  • type shot__task :

{ 
  'project': 'hamlet', 
  'type': 's', 
  'sequence': 'sq030', 
  'shot': 'sh0010',
  'task': 'animation' 
}
  • type asset__version :

{ 
  'project': 'hamlet', 
  'type': 'a', 
  'cat': 'props', 
  'name': 'skull',
  'task': 'modeling',
  'version': 'v008' 
}

For more about Sid types, please check out the glossary.

If the Sid contains search characters (eg. *, **, <, >) it is considered a “search Sid”.
A Search Sid can be typed or not, or can resolve to multiple types.

"hamlet/s/sq030/*"  # is typed: shot__shot
"hamlet/s/sq030/**"  # will resolve to multiple types, because of the recursive "**"

(See more on searches below).

API Usage examples

Sid creation and manipulation

from spil import Sid

# create a Sid from scratch
task = Sid("hamlet/s/sq030/sh0010/render")
# a task sid: hamlet/s/sq030/sh0010/render

# create a Sid by changing values
anim_task = task.get_with(task="anim")          
# task sid: hamlet/s/sq030/sh0010/anim 

# create a Sid from a Sids hierarchy 
sequence = task.get_as('sequence')              
# sequence sid: hamlet/s/sq030

# another way
shot = task.parent                              
# shot sid: hamlet/s/sq030/sh0010 

Parts of the Sid’s API are inspired by the pathlib https://www.python.org/dev/peps/pep-0428

from spil import Sid
shot = Sid("hamlet") / "s" / "sq030" / "sh0010"

Creation with a Query or dictionary

from spil import Sid
seq = Sid(query="project=hamlet&type=s&sequence=sq010")  # query        
seq = Sid(fields={'project': 'hamlet', 'type': 's', 'sequence': 'sq010'})  # dict

A Sid is immutable. Methods returning Sids support method chaining.

from spil import Sid
s = (Sid()
     .get_with(project="hamlet", type="s")
     .get_with(query="sequence=sq010&shot=sh0010&task=anim")
     .get_as('project'))
print(s)  

(Note that this chain doesn’t make any sense, since the Sid is just “hamlet” in the end…)

Access data about the Sid: by key, as a complete dictionary, as string or Query.

from spil import Sid 
shot = Sid("hamlet/s/sq030/sh0010")

# get a field of the sid by key
shot.get("sequence")   
# sq030

# as a dictionary
shot.fields            
#  { 'project': 'hamlet', 'type': 's', 'sequence': 'sq030', 'shot': 'sh0010' }

# as a Query
shot.as_query()          
# "project=hamlet&type=s&seq=sq030&shot=sh0010"

# "uri": type and string
shot.uri        
# "shot__shot:hamlet/s/sq030/sh0010" 

Path Resolver

The Sid can be resolved to and from paths.
Multiple configurations can co-exist.
For example “local”, “server”, “linux”, etc. paths.

from spil import Sid

# creating a Sid from path
scene = Sid(path="/projects/hamlet/chars/ophelia/modeling/v002/publish/ophelia_model.mb")

print(scene)            
# "hamlet/a/chars/ophelia/modeling/v002/p/mb"

# returning default path
path = scene.path()     
# "/projects/hamlet/chars/ophelia/modeling/v002/publish/ophelia_model.mb"

# returning path from "server" configuration
path = scene.path("server")     
# "/server/projects/hamlet/chars/ophelia/modeling/v002/publish/ophelia_model.mb"

Example in maya, with an opened scene file:

import maya.cmds as cmds
from spil import Sid

# Get the current scene's path
scene_path = cmds.file(query=True, sceneName=True)

# build the Sid
scene = Sid(path=scene_path)

# use the Sid
if scene:  # A sid that is not resolvable (not conform), has not type, and evaluates to False.
    print(scene.get('project'))  # hamlet
    print(scene.get('version'))  # "v002"
else:
    print("opened scene is not a pipeline scene")

Data access and Pipeline workflows

Sid wraps common requests, that are internally delegated to configurable data sources (Getters and Writers).

from spil import Sid
task_sid = Sid("hamlet/s/sq030/sh0010/layout") 

task_sid.exists()                 # True
version_sid = task_sid.get_last('version')      # "hamlet/s/sq030/sh0010/layout/v003"

Sids API can intuitively express common pipeline workflows.

from spil import Sid
task_sid = Sid("hamlet/s/sq030/sh0010/layout") 

if task_sid.exists():
  print( task_sid.get_last('version').get_attr('comment') )     # "Changed camera angle."

# match() is handy for hooks and action overrides
if task_sid.match('hamlet/s/*/*/layout/**/maya'):  
    # do something specific for hamlet maya layouts
    ... 

Finding Sids

It is possible to query Sids using a glob-like syntax.

Operators:

  • * : star search

  • ** : recursive star search

  • > : last

  • , : “or”

  • configurable aliases (“movie” -> “mov,avi,mp4”, “maya” -> “ma,mb”)

Search Examples

  • “All the Shots of sequence sq030” ?

"hamlet/s/sq030/*"
  • “All the published maya files of Ophelias modeling” ?

"hamlet/a/chars/ophelia/model/*/p/maya"
  • “Last published render movies for the project hamlet” ?

"hamlet/s/**/render/>/p/movie"
  • “All cache files for hamlet’s sequence 30, shot 10” ?

"hamlet/s/sq030/sh010/**/cache"

Finders

To launch queries, Spil implements Finder classes that access different data sources.

  • FindInPaths: to search the file system

  • FindInList: to search a list

  • FindInCache: to search a cache

  • FindInAll: to search other Finders, depending on a configuration

  • FindInShotgrid: to search Shotgrid

Finders implement find(), do_find() find_one()andexists()`.

# Look up the last published versions for given shot, on the File System 
from spil import FindInPaths as Finder
for sid in Finder().find("hamlet/s/sq010/sh0010/**/>/p/movie"):
  print(sid)

# "hamlet/s/sq010/sh0010/layout/v012/p/mov"
# "hamlet/s/sq010/sh0010/animation/v003/p/avi"
# "hamlet/s/sq010/sh0010/render/v001/p/mov"
# ...

The FindInShotgrid is an example Finder implementation.
It may need to be adapted, depending on the production’s Shotgrid usage.

This page is work in progress.