DI Transition Guide
Here are some notes of what is involved in converting your plug-ins to a dependency injection-style of working.
Note that none of this is fixed and is very debatable at the moment, so if you have any concerns or input, now is a good time.
- In cases where you have either
process_context or process_instance, a simple search-and-replace to process will work fine.
- In cases where you have both, see below.
- For
process() to be called, it must either ask for context and/or instance. If neither is present, process() will not be called at all. See below.
- During the transition phase, the distinction is made internally by looking for the existence of a
process_context or process_instance method.
- If either exist, the plug-in is deemed “old-style” and is processed using the current implementation.
- If both
process and either process_context or process_instance is present, old-style wins and process will not be called.
I’ll update the list as more things come to mind. So far, updating the entire Napoleon extension took less than a minute and was a matter of a simple search-and-replace, leaving the behaviour unspoiled.
Both process_context and process_instance
The current behaviour of this is for process_context to be processed first, followed by process_instance. This behaviour isn’t possible any more. You can however process both in the same function.
def process(self, context, process):
# do things
In case you do have both, process_instance will overwrite process_context due to your plug-in being re-written to a it’s Dependency Injection equivalent at run-time.
def process_context(self, context):
# I will not be called. :(
def process_instance(self, instance):
# Runs as usual
Old-first
The reason for looking for old-style methods before new-style is because of the newly introduced ability to use __init__. In cases where __init__ is used, and process not being implemented, the plug-in is still deemed new-style as __init__ is assumed to not have been in use.
Empty process()
If neither context nor instance is present in the signature of process(), nothing happens.
I struggled to provide the ability to implement “anonymous” processes, for things that do something unrelated to either the Context nor Instance, but primarily to aid in the initial learning phase.
For example.
class MyPlugin(...):
def process(self):
cmds.file(exportSelected=True)
This could be a user’s first plug-in. From here, he could learn about the benefits of using Context and thereafter Instance, and thereby learning about why they exist in the first place. Baby-step style.
But, I just can’t for the life of me figure out how to do that in a way that makes sense.
For example, in this case.
class ValidateInstanceA(pyblish.Validator):
families = ["familyA"]
def process(self, instance):
# validate the instance
It’s quite clear that when there isn’t an instance suitable to this family, process should not be called.
However.
class ValidateInstanceA(pyblish.Validator):
families = ["familyA"]
def process(self, context):
# validate the context
What about now? The context isn’t dependent on a family, but should always be called regardless. So clearly, process is called, even if no compatible instance is present.
Which brings us to.
class ValidateInstanceA(pyblish.Validator):
families = ["familyA"]
def process(self):
# do something simple
What happens now? Should it be called?
I considered letting it run if the arguments are either empty, or context is present. But that doesn’t work if other arguments are to be injected.
class ValidateInstanceA(pyblish.Validator):
families = ["familyA"]
def process(self, time):
# do something simple with time
Thoughts?