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?