Skip to content

Releases: pyblish/pyblish-base

1.1.3

18 Jul 06:43
Compare
Choose a tag to compare

Version 1.1.3

  • Feature: Dict-like getting of instances from Context (#208)
  • Feature: Host registration (#177)
  • collect and integrate now available via pyblish.util
  • "asset" available in context.data("result") for forwards compatibility
  • Bugfix: Decrementing order actually works now. (#206)

Context getter

You can now reference Instance's by "id" directly from a Context.

import pyblish.api
context = pyblish.api.Context()
context.create_instance("MyInstance")
my_instance = context["MyInstance"]

id is generally the same as an Instance's name.

Host integration

This replaces the current behaviour and use of pyblish.api.current_host().

Practically, everything will still work, including current_host() (which is now deprecated, read on) with the added requirement that an integration must be loaded for plug-ins to filter against it.

For example, when you load Maya, it's the Pyblish for Maya integration that registers the host, maya. If this doesn't happen, then plug-ins filtered by hosts = ["maya"] won't run.

You have most likely already done this, as it's how Pyblish QML automatically registers itself as well, but in the rare case where you are using a host, along with plug-ins filtered by that host, but haven't registered the integration, you will notice a change in behaviour.

New functions

Like mentioned above, current_host is still alive and well, but is to be considered deprecated, as it will only return the last registered host. I've made it so that Maya, for example, registers mayapy, mayabatch, and maya in this order, meaning current_host will still return the expected maya for backwards compatibility.

Henceforth, registered_hosts() is the official method with which to query which hosts are currently supported.

>>> import pyblish.api
>>> pyblish.api.registered_hosts()
["python", "mayabatch", "mayapy", "maya"]

python is automatically registered during initialisation, but can be removed, along with every other hosts, should you need, via deregister_all_hosts().

Here are all the new functions related to this functionality.

  • register_host
  • registered_hosts
  • deregister_host
  • deregister_all_hosts

1.1.2

25 Jun 16:45
Compare
Choose a tag to compare

Version 1.1.2

  • Logic: Excluding SimplePlugin and Selectors from Default test (See #198)
  • BACKWARDS INCOMPATIBLE order now supports being decremented (see #199)

1.1.1

09 Jun 16:10
Compare
Choose a tag to compare

Maintenance update.

Version 1.1.1

  • Enhancement: Hosts limit, not allow (see #194)
  • Enhancement: CLI outputs less, more concise information
  • Enhancement: Lowering logging level for plug-ins skipped during discovery to DEBUG
  • Enhancement: Underscore-prefixed plug-ins are hidden from discovery (see #196)
  • Bugfix: Discover ignores non-Python files (see #192)

1.1.0

04 Jun 14:28
Compare
Choose a tag to compare

Pyblish 1.1

Version 1.1 is now available and includes the following new features.




Dependency Injection

The most prominent change is this.

Before illustrating how it works, it's important to point out that this is the new way of writing plug-ins. It means that the current way of implementing plug-ins still works, but are to be considered deprecated and no longer supported.

Now, on to the fun stuff!

As Usual

import pyblish.api

class ValidateInstances(pyblish.api.Validator):
    def process(self, instance):
        pass

This does as you would expect. Which is to process once for every instance, regardless of family (see below for new family defaults).

import pyblish.api

class SelectInstances(pyblish.api.Selector):
    def process(self, context):
        pass

In the same spirit, this plug-in runs once and has access to the context. This is nothing new.

Plug-in Independency

What is new is that you can choose to process nothing.

import pyblish.api

class SimpleExtractScene(pyblish.api.Extractor):
    def process(self):
        cmds.file("myfile.mb", exportAll=True)

This plug-in runs once, as when processing the context, but doesn't have access to either the current Instance nor Context. This can be useful for plug-ins that are completely independent of it's environment and state.

Default Services

What is also new is that you can also request other so-called "services".

import pyblish.api

class CustomValidator(pyblish.api.Validator):
    def process(self, user, time):
        fname = "myfile_v001_%s_%s.mb" % (user, time())
        cmds.file(fname, exportAll=True)

In which case the services user, time and config are injected into the plug-in during process. Each of which are default services that ship with the Pyblish base install.

Here are all of them.

register_service("user", getpass.getuser())
register_service("time", pyblish.lib.time)
register_service("config", pyblish.api.config)
  • user is available by value, as it is not expected to change at run-time.
  • time is callable, as it provides unique values each time it is used
  • config is shorthand to pyblish.api.config

User Defined Services

You can also register your own services..

def say(something, yell=False):
    print(something.upper() if yell else something)

pyblish.api.register_service(say)

..and then request them via your plug-ins.

import pyblish.api

class ValidateUniverse(pyblish.api.Validator):
    def process(self, say):
        say("I just wanted to say, Hello World!", yell=True)

Service Coordination

Services are shared amongst plug-ins.

datastore = {"softFailure": False}
pyblish.api.register_service("store", datastore)

Which means you can use it to communicate and pass information inbetween them.

class ValidatePrimary(pyblish.api.Validator):
    def process(self, instance, store):
        if instance.has_data("I'm kind of valid.."):
            store["softFailure"] = True


class ValidateBackup(pyblish.api.Validator):
    def process(self, instance, store):
        if store["softFailure"] is True:
            # Do alternate validation

Or to provide globally accessible data, such as a database connection.

import ftrack
import pyblish.api
proxy = ftrack.ServerProxy("http://myaddress.ftrack.com")
pyblish.api.register_service("ftrack", proxy)

Distributed Development

With services, you can defer development of a plug-in between more than a single developer allowing for faster iteration times and improved version control.

As a plug-in is developed, requirements may arise..

import pyblish.api

class ValidateSecretSauce(pyblish.api.Validator):
    def process(self, instance, sauce):
        if sauce.hot():
            assert instance.has_data("hotCompatible"), "Sauce too hot!"
        assert instance.data("tasty") == True, "Sauce not tasty!"

Which can later be developed.

import pyblish.api
import my_studio_tools

class Sauce(object):
    def hot(self):
        return my_studio_tools.hot_sauce()

pyblish.api.register_service("sauce", Sauce())

Testing

As a final and important piece to the puzzle, dependency injection makes testing easier and more controllable.

def test_plugin():
    """Testing of a host-dependent plug-in with DI"""
    instances = list()

    class SelectCharacters(pyblish.api.Validator):
        def process(self, context, host):
            for char in host.ls("*_char"):
                instance = context.create_instance(char, family="character")
                instance.add(host.listRelatives(char))
                instances.append(instance.name)

    class HostMock(object):
        def ls(self, query):
            return ["bobby_char", "rocket_char"]

        def listRelatives(self, node):
            if node == "bobby_char":
                return ["arm", "leg"]
            if node == "rocket_char":
                return ["propeller"]
            return []

    pyblish.api.register_service("host", HostMock())

    for result in pyblish.logic.process(
            func=pyblish.plugin.process,
            plugins=[SelectCharacters],
            context=pyblish.api.Context()):
        assert_equals(result["error"], None)

    assert_equals(len(instances), 2)
    assert_equals(instances, ["bobby_char", "rocket_char"])

Related




Simple Plug-ins

A new type of plug-in has been introduced; the superclass of the currently available Selection, Validation, Extraction and Conform (SVEC) plug-ins - called simply Plugin.

import pyblish.api

class MyPlugin(pyblish.api.Plugin):
  def process(self):
    self.log.info("I'm simple")

Simple plug-ins are just that, a simpler, less assuming variant of SVEC. Each inherit the exact same functionality and can be used in-place of any other plug-in, the only difference being a default order of -1 meaning they will run before any of it's siblings.

Other than that, they are identical in every way. To make it into a Selector, simply assign it an appropriate order.

class MySelector(pyblish.api.Plugin):
  order = pyblish.api.Selector.order

More importantly, simple plug-ins are meant as a stepping stone for beginners not yet familiar with SVEC, and as a bridge to unforseen use of Pyblish, allowing arbitrary use and boundless extensibility.

With this, Pyblish is now a generic automation framework with SVEC becoming a collection of best practices and recommended method of writing plug-ins.

Related




In-memory plug-ins

This new feature will allow you to debug, share and prototype plug-ins more quickly.

In-memory plug-ins come directly from the Python run-time and isn't dependent on a filesystem search, which means you can easily post a plug-in to someone else. Once registered, it will be processed like any other plug-in.

import pyblish.api

class SelectPrototypeInstance(pyblish.api.Selector):
    def process(self, context):
        instance = context.create_instance("Prototype Test")
        instance.set_data("family", "prototype")

pyblish.api.register_plugin(SelectPrototypeInstance)

This can be done anytime prior to publishing, including whilst the GUI is open, which means you can do some pretty intense things to hunt down bugs.

import pyblish.api

data = {}

@pyblish.api.log
class MyPlugin(pyblish.api.Plugin):
    def process(self):
        data["key"] = "value"

pyblish.api.register_plugin(MyPlugin)

After publishing, data will contain the key key with value value. This is an example of a plug-in reaching out into the current execution environment. Something not possible before.

Related functions




New Defaults for Families and Hosts

The attributes families and hosts now default to *, which means that they process everything in sight, unless you tell it not to.

This is different from how it was before, which was to process nothing, unless you told it to.

This has no effect on your current plug-ins, as you were obligated to always provide a family if you wanted it to process, but does mean it is a non-reversible change. So, fingers crossed you like it!




Custom Test

You can now take control over when publishing is cancelled.

Currently, every plug-in is processed, unless the next plug-in is of an order above 2 (i.e. not a Selector nor Validator) and no prior plug-in within the orders 1-2 (i.e. any Validator) have failed.

This is what that test looks like.

def default_test(**vars):
    if vars["nextOrder"] >= 2:  # If validation is done
        for order in vars["ordersWithError"]:
            if order < 2:  # Were there any error before validation?
                return "failed validation"
    return

The test is run each time a new plug-in is about to process, and is given a dictionary vars which is always up to date with the most recent information.

Currently, the only two members of the dictionary is nextOrder...

Read more

1.0.16

16 May 10:05
Compare
Choose a tag to compare

Version 1.0.16

  • Feature: The Pyblish CLI is back!
  • API: Added pyblish.api.sort()
  • API: Added pyblish.api.current_host()
  • API: Plug-in paths can no longer be modified by altering
    the results returned from pyblish.api.plugin_paths()
  • API: Paths are no longer made absolute during registration.

CLI

You can now invoke Pyblish from the command-line.

$ pyblish --help
Usage: pyblish [OPTIONS] COMMAND [ARGS]...

  Pyblish command-line interface

  Use the appropriate sub-command to initiate a publish.

  Use the --help flag of each subcommand to learn more about what it can
  do.

  Usage:
      $ pyblish publish --help
      $ pyblish test --help

Options:
  --verbose                       Display detailed information. Useful for
                                  debugging purposes.
  --version                       Print the current version of Pyblish
  --paths                         List all available paths
  --plugins                       List all available plugins
  --registered-paths              Print only registered-paths
  --environment-paths             Print only paths added via environment
  --configured-paths              Print only paths added via configuration
  -pp, --plugin-path TEXT         Replace all normally discovered paths with
                                  this This may be called multiple times.
  -ap, --add-plugin-path TEXT     Append to normally discovered paths.
  -c, --config TEXT               Absolute path to custom configuration file.
  -d, --data TEXT...              Initialise context with data. This takes
                                  two arguments, key and value.
  -ll, --logging-level [debug|info|warning|critical|error]
                                  Specify with which level to produce logging
                                  messages. A value lower than the default
                                  'warning' will produce more messages. This
                                  can be useful for debugging.
  --help                          Show this message and exit.

Commands:
  config   List available config.
  publish  Publish instances of path.

Available sub-commands are:

  • publish
  • config
$ pyblish publish --help
Usage: pyblish publish [OPTIONS] [PATH]

  Publish instances of path.

  Arguments:
      path: Optional path, either absolute or relative,
          at which to initialise a publish. Defaults to
          the current working directory.

  Usage:
      $ pyblish publish my_file.txt --instance=Message01
      $ pyblish publish my_file.txt --all

Options:
  -i, --instance TEXT  Only publish specified instance. The default behaviour
                       is to publish all instances. This may be called
                       multiple times.
  -de, --delay FLOAT   Add an artificial delay to each plugin. Typically used
                       in debugging.
  --help               Show this message and exit.

Custom Data

You can add data to the Context from the command-line as well, here's an example of how that works.

$ pyblish --data key value --data key2 value2 publish

Each time --data is called, with it's two arguments (key, value), each item is added to the Context before plug-ins start running.

1.0.15

07 Apr 09:47
Compare
Choose a tag to compare

Primarily and addition of the .id attribute on instances and plug-ins to uniquely identify them. Currently defaults to their name so as to not break backwards compatibility, but opens up doors for more unique identifiers should the need occur.

Example

>>> import pyblish.api
>>> instance = pyblish.api.Instance("MyInstance")
>>> instance.id
MyInstance
>>> plugin = pyblish.api.discover()[0]
>>> plugin.id
NameOfPlugin

Version 1.0.15

  • API: Plugin.repair_* documented and implemented by default
  • API: Added lib.where()
  • API: Added .id attribute to instances and plug-ins

1.0.14

27 Mar 11:55
Compare
Choose a tag to compare

Version 1.0.14

Minor change in processing logic; has no effect on the current pyblish.main.publish() / pyblish.util.publish() or associated convenience functions, but may have a (positive) effect on custom implementations that previously had to handle getting (None, None) when neither context nor instances were processed.

Full changelist

  • Added pyblish.api.version
  • Matched verbosity level from processing context as the processing of instances.
  • Processing logic change; processing of plug-in without compatible instances will now not yield anything; previously it yielded a pair of (None, None).

1.0.13

19 Mar 10:28
Compare
Choose a tag to compare

Version 1.0.13

  • Added pyblish.api.sort_plugins
  • Added ordered output to pyblish.api.discover
  • pyblish.api.plugins_by_family now yields correct results
    for plug-ins with wildcard families.
  • Refactored main.py into util.py

1.0.12

14 Feb 20:36
Compare
Choose a tag to compare

Version 1.0.12

Maintenance release.

  • plugin.py reloadable without loosing currently loaded plug-ins
  • Basic plug-in manager "Manager"
  • Simplified configuration (no more user or custom configuration)
  • Simplifying discover() (no more indirection)
  • Adding default logger (good bye "No logger found..")
  • Temporarily removig CLI
  • Context is no longer a Singleton
  • Added forwards compatibility for Collector plug-in

1.0.11

01 Dec 10:07
Compare
Choose a tag to compare
Merge pull request #129 from mottosso/master

Complementing Pyblish Frontend