2. Services
DI opens up doors for added functionality not before possible.
def process(self, context, instance):
# the function is given the current Context, and Instance
The above mimics the current behaviour, with slightly less typing and options for excluding both Context
and Instance
from the function signature where needed.
But it also means the ability to inject custom functionality.
def process(self, instance, time, user):
print("%s was published @ %s by %s" % instance.data("name"), time(), user)
In which time
and user
are injected on-demand, providing additional functionality to the plug-in. In this case, a callable function time
which returns the current time, and a static value user
.
Furthermore, services can be registered by developers.
import pyblish.api
pyblish.api.register_service(
"time", lambda: datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%fZ"))
In the above, a custom service time
is registered and made available to plug-ins, providing a pre-formatted version the current time, such that every plug-in uses the same formatting and needn’t concern themselves with maintaining any updates to it.
Services vs. Data
Where does the line go between what is data and what is a service?
If data, added via e.g. Context.set_data(key, value)
, represents data shared amongst plug-ins, services may represent shared functionality.
Though there is technically nothing preventing you from storing callables as data…
import time
context.set_data("time", lambda: time.time)
Just as there is technically nothing preventing you from providing constants as a service.
pyblish.api.register_service("user", getpass.getuser())
It may make sense from a maintenance point of view to make the data/function separation. This way, data can be kept constant which simplifies archiving and visualisation, like passing the entire thing to a database, whereas functionality can be kept free of constants.
Open questions
Is additional services something we need, or does it add complexity? When a plug-in requests a service that isn’t available, when do we throw an error?
def process(self, not_exist):
pass
- Thrown during discovery
- Thrown during processing, e.g. in the GUI
- Silently skipped; rely on external tool for checking correctness.
# Checking correctness
$ pyblish check select_something.py
Plug-in is valid.