|
import re |
|
import pyblish.api |
|
import pyblish.util |
|
|
|
disk = {} |
|
|
|
|
|
class ValidateHeight(pyblish.api.Validator): |
|
tags = ["character", "measurement"] |
|
|
|
# Schema is used to build the User Interface |
|
# and validate incoming values. |
|
schema = { |
|
"height": float, |
|
"tolerance": float |
|
} |
|
# Options used to populate default values |
|
# in user interface and for final evaluation |
|
# by process(). |
|
options = { |
|
"height": 2, |
|
"tolerance": 0.5 |
|
} |
|
|
|
def process(self, instance): |
|
self.log.info("%s compared with %s" % ( |
|
instance.data("height"), self.options["height"])) |
|
|
|
low_bound = self.options["height"] - self.options["tolerance"] |
|
high_bound = self.options["height"] + self.options["tolerance"] |
|
assert low_bound < instance.data("height") < high_bound, ( |
|
"Height out of bounds") |
|
|
|
|
|
class ValidatePivot(pyblish.api.Validator): |
|
tags = ["geometry", "character", "film"] |
|
options = { |
|
"predicate": "zeroed" |
|
} |
|
schema = { |
|
"predicate": [ |
|
"zeroed", |
|
"straight", |
|
"transform_only" |
|
] |
|
} |
|
|
|
def process(self, instance): |
|
if self.options["predicate"] == "zeroed": |
|
assert False |
|
if self.options["predicate"] == "straight": |
|
assert True |
|
|
|
|
|
class ValidateNamingComplex(pyblish.api.Validator): |
|
tags = ["naming", "games", "tv", "film"] |
|
options = { |
|
# Anything suffixed with an uppercase |
|
# three letter extension |
|
"regex": "^.*_[A-Z]{3}$" |
|
} |
|
schema = { |
|
"regex": str |
|
} |
|
|
|
def process(self, instance): |
|
for child in instance: |
|
assert re.match(self.options["regex"], child), ( |
|
"Invalid name for at least %s" % child) |
|
|
|
|
|
class ValidateNamingSimple(pyblish.api.Validator): |
|
tags = ["naming", "games", "tv", "film"] |
|
options = { |
|
"prefix": False, |
|
"prefixLength": 3, |
|
"prefixCase": "upper", |
|
"suffix": True, |
|
"suffixLength": 3, |
|
"suffixCase": "upper", |
|
"separator": "_", |
|
} |
|
schema = { |
|
"prefix": bool, |
|
"prefixLength": int, |
|
"prefixCase": ["upper", "lower"], |
|
"suffix": bool, |
|
"suffixLength": int, |
|
"suffixCase": ["upper", "lower"], |
|
"separator": str |
|
} |
|
|
|
def process(self, instance): |
|
for child in instance: |
|
regex = "^.*_[A-Z]{suffixLength}$".format(**self.options) |
|
assert re.match(regex, child), ( |
|
"Invalid name for at least %s" % child) |
|
|
|
|
|
class ValidateDefaultPose(pyblish.api.Validator): |
|
tags = ["rigging", "animation", "consistency"] |
|
options = { |
|
"tolerance": 0.01, |
|
"considerUserDefined": True, |
|
"considerBuiltin": True |
|
} |
|
schema = { |
|
"tolerance": float, |
|
"considerUserDefined": bool, |
|
"considerBuiltin": bool |
|
} |
|
|
|
def process(self, instance): |
|
assert True |
|
|
|
|
|
# Two basic gatekeepers |
|
class CollectInstances(pyblish.api.Collector): |
|
def process(self, context): |
|
context.create_instance( |
|
name="MyInstance", |
|
family="rig", |
|
height=1.86) |
|
|
|
|
|
class ExtractCharacter(pyblish.api.Extractor): |
|
def process(self, instance): |
|
disk["data"] = 0x05f4 |
|
|
|
|
|
# Database of all available validators |
|
# Typically stored elsewhere, somewhere global |
|
validators = [ |
|
ValidatePivot, |
|
ValidateHeight, |
|
ValidateNamingComplex, |
|
ValidateNamingSimple, |
|
ValidateDefaultPose, |
|
] |
|
|
|
|
|
def search(queries, config=None, inclusive=False): |
|
"""Search engine, based on tags and inclusiveness |
|
|
|
Search amongst available validators via keywords. |
|
Optionally exlude individual validators by name. |
|
|
|
Arguments: |
|
queries (list): Individual tags, e.g. "film" and "games" |
|
config (dict): Options per plug-in |
|
|
|
""" |
|
|
|
plugins = list() |
|
options = config.get("options", dict()) |
|
exclude = config.get("exclude", list()) |
|
|
|
for validator in validators: |
|
name = validator.__name__ |
|
if name in exclude: |
|
continue |
|
|
|
operator = any if inclusive else all |
|
if not operator(tag in validator.tags for tag in queries): |
|
continue |
|
|
|
# Produce a copy to modify with options |
|
copy = type(name, (validator,), {}) |
|
copy.options.update(options.get(name, {})) |
|
|
|
plugins.append(copy) |
|
|
|
return plugins |
|
|
|
|
|
# A full configuration file, provided externally |
|
config = { |
|
|
|
# Options provided by the user either a GUI or file on disk |
|
"options": { |
|
"ValidatePivot": { |
|
"predicate": "straight" |
|
}, |
|
"ValidateHeight": { |
|
"height": 1.80, |
|
"tolerance": 0.1 |
|
}, |
|
"ValidateNamingComplex": { |
|
"regex": "^.*_[A-Z]{4}$" |
|
} |
|
}, |
|
|
|
# Provided via GUI or file, via e.g. unticking in a visual list |
|
"exclude": [ |
|
"ValidateNamingSimple" |
|
] |
|
} |
|
|
|
|
|
# Perform search |
|
validators = search( |
|
queries="naming film measurement".split(), |
|
config=config, |
|
inclusive=True) |
|
|
|
# Register found |
|
pyblish.api.deregister_all_plugins() |
|
for plugin in validators + [CollectInstances, ExtractCharacter]: |
|
pyblish.api.register_plugin(plugin) |
|
|
|
# Perform publish |
|
context = pyblish.util.publish() |
|
for result in context.data("results"): |
|
if result["instance"] is None: |
|
continue |
|
|
|
# Report results |
|
print("{instance.id} + {plugin.id} = {success}".format(**result)) |