So here is a simple importer example that looks for files on the desktop, and references them in;
import os
import pyblish_qml
import pymel.core
class CollectFiles(pyblish.api.Collector):
"""
"""
def process(self, context):
path = os.path.join(os.path.dirname(os.path.expanduser('~')), 'Desktop')
for f in os.listdir(path):
ext = os.path.splitext(f)[1]
valid_ext = ['.mb', '.ma']
if ext in valid_ext:
instance = context.create_instance(name=f)
instance.set_data('family', value='desktopFiles')
instance.set_data('path', value=os.path.join(path, f))
instance.set_data("publish", False)
class ReferenceFile(pyblish.api.Validator):
def process(self, instance):
path = instance.data('path')
name = os.path.basename(path)
pymel.core.system.createReference(instance.data('path'), namespace=name)
pyblish.api.register_plugin(ReferenceFile)
pyblish.api.register_plugin(CollectFiles)
import pyblish_maya
pyblish_qml.settings.WindowTitle = 'Importer'
pyblish_maya.show()
The main problem here is the configuration of where to look for the files/data. This would be something the user would have to choose. This would be same problem if querying a server like Ftrack.
Here is an example of an updator, that we actually use in production to check if the scene is using the latest version:
import os
import re
import pyblish.api
import pymel
import pyblish_qml
class CollectReferences(pyblish.api.Collector):
"""
"""
def process(self, context):
for node in pymel.core.ls(type='reference'):
if 'sharedReferenceNode' in node.name():
continue
if node.isReferenced():
continue
file_ref = pymel.core.system.FileReference(node)
try:
self.log.info(file_ref.path)
except:
continue
if not file_ref.isLoaded():
continue
instance = context.create_instance(name=node.name())
instance.set_data('family', value='reference')
instance.add(node)
instance.set_data("publish", False)
class ValidateReferenceVersion(pyblish.api.Validator):
""" Validates that the current reference path is the latest version.
"""
families = ['reference']
label = 'Reference Version'
optional = True
def version_get(self, string, prefix, suffix = None):
"""Extract version information from filenames used by DD (and Weta, apparently)
These are _v# or /v# or .v# where v is a prefix string, in our case
we use "v" for render version and "c" for camera track version.
See the version.py and camera.py plugins for usage."""
if string is None:
raise ValueError, "Empty version string - no match"
regex = "[/_.]"+prefix+"\d+"
matches = re.findall(regex, string, re.IGNORECASE)
if not len(matches):
msg = "No \"_"+prefix+"#\" found in \""+string+"\""
raise ValueError, msg
return (matches[-1:][0][1], re.search("\d+", matches[-1:][0]).group())
def version_set(self, string, prefix, oldintval, newintval):
"""Changes version information from filenames used by DD (and Weta, apparently)
These are _v# or /v# or .v# where v is a prefix string, in our case
we use "v" for render version and "c" for camera track version.
See the version.py and camera.py plugins for usage."""
regex = "[/_.]"+prefix+"\d+"
matches = re.findall(regex, string, re.IGNORECASE)
if not len(matches):
return ""
# Filter to retain only version strings with matching numbers
matches = filter(lambda s: int(s[2:]) == oldintval, matches)
# Replace all version strings with matching numbers
for match in matches:
# use expression instead of expr so 0 prefix does not make octal
fmt = "%%(#)0%dd" % (len(match) - 2)
newfullvalue = match[0] + prefix + str(fmt % {"#": newintval})
string = re.sub(match, newfullvalue, string)
return string
def get_latest_version(self, node):
file_ref = pymel.core.system.FileReference(node)
basename = os.path.basename(file_ref.path)
version_string = self.version_get(basename, 'v')[1]
version = int(version_string)
head = basename.split(version_string)[0]
ext = os.path.splitext(basename)[1]
max_version = version
path = basename
for f in os.listdir(os.path.dirname(file_ref.path)):
if ext != os.path.splitext(f)[1]:
continue
# fail safe against files without version numbers
try:
f_version_string = self.version_get(f, 'v')[1]
except:
continue
if head != f.split(f_version_string)[0]:
continue
v = int(self.version_get(f, 'v')[1])
if max_version < v:
max_version = v
path = f
return path
def process(self, instance):
node = instance[0]
file_ref = pymel.core.system.FileReference(node)
basename = os.path.basename(file_ref.path)
msg = 'Newer reference version available for %s' % file_ref.path
assert self.get_latest_version(node) == basename, msg
def repair(self, instance):
node = instance[0]
file_ref = pymel.core.system.FileReference(node)
basename = os.path.basename(file_ref.path)
if self.get_latest_version(node) != basename:
new_basename = self.get_latest_version(node)
new_path = os.path.join(os.path.dirname(file_ref.path),
new_basename)
file_ref.replaceWith(new_path)
pyblish.api.register_plugin(CollectReferences)
pyblish.api.register_plugin(ValidateReferenceVersion)
import pyblish_maya
pyblish_qml.settings.WindowTitle = 'Importer'
pyblish_maya.show()
The problem with this updator is adding functionality to choose which version to update to, or if you want to version down. This could probably be achieved with the new Actions though, but as an overview for the user it might be a little difficult to see what is available.