mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 12:54:40 +01:00
Publish: Enhance automated publish plugin settings (#4986)
* prepared helper functions for custom settings apply method * publish plugin can have 'settings_category' attribute to define settings category * Better 'settings_category' comment Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com> * fix trailing spaces * added more information about pyblish plugins to dev docs --------- Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com>
This commit is contained in:
parent
136af34a71
commit
30fe6759c3
3 changed files with 136 additions and 23 deletions
|
|
@ -36,6 +36,9 @@ from .lib import (
|
|||
context_plugin_should_run,
|
||||
get_instance_staging_dir,
|
||||
get_publish_repre_path,
|
||||
|
||||
apply_plugin_settings_automatically,
|
||||
get_plugin_settings,
|
||||
)
|
||||
|
||||
from .abstract_expected_files import ExpectedFiles
|
||||
|
|
@ -80,6 +83,9 @@ __all__ = (
|
|||
"get_instance_staging_dir",
|
||||
"get_publish_repre_path",
|
||||
|
||||
"apply_plugin_settings_automatically",
|
||||
"get_plugin_settings",
|
||||
|
||||
"ExpectedFiles",
|
||||
|
||||
"RenderInstance",
|
||||
|
|
|
|||
|
|
@ -355,29 +355,55 @@ def publish_plugins_discover(paths=None):
|
|||
return result
|
||||
|
||||
|
||||
def _get_plugin_settings(host_name, project_settings, plugin, log):
|
||||
def get_plugin_settings(plugin, project_settings, log, category=None):
|
||||
"""Get plugin settings based on host name and plugin name.
|
||||
|
||||
Note:
|
||||
Default implementation of automated settings is passing host name
|
||||
into 'category'.
|
||||
|
||||
Args:
|
||||
host_name (str): Name of host.
|
||||
plugin (pyblish.Plugin): Plugin where settings are applied.
|
||||
project_settings (dict[str, Any]): Project settings.
|
||||
plugin (pyliblish.Plugin): Plugin where settings are applied.
|
||||
log (logging.Logger): Logger to log messages.
|
||||
category (Optional[str]): Settings category key where to look
|
||||
for plugin settings.
|
||||
|
||||
Returns:
|
||||
dict[str, Any]: Plugin settings {'attribute': 'value'}.
|
||||
"""
|
||||
|
||||
# Use project settings from host name category when available
|
||||
try:
|
||||
return (
|
||||
project_settings
|
||||
[host_name]
|
||||
["publish"]
|
||||
[plugin.__name__]
|
||||
)
|
||||
except KeyError:
|
||||
pass
|
||||
# Plugin can define settings category by class attribute
|
||||
# - it's impossible to set `settings_category` via settings because
|
||||
# obviously settings are not applied before it.
|
||||
# - if `settings_category` is set the fallback category method is ignored
|
||||
settings_category = getattr(plugin, "settings_category", None)
|
||||
if settings_category:
|
||||
try:
|
||||
return (
|
||||
project_settings
|
||||
[settings_category]
|
||||
["publish"]
|
||||
[plugin.__name__]
|
||||
)
|
||||
except KeyError:
|
||||
log.warning((
|
||||
"Couldn't find plugin '{}' settings"
|
||||
" under settings category '{}'"
|
||||
).format(plugin.__name__, settings_category))
|
||||
return {}
|
||||
|
||||
# Use project settings based on a category name
|
||||
if category:
|
||||
try:
|
||||
return (
|
||||
project_settings
|
||||
[category]
|
||||
["publish"]
|
||||
[plugin.__name__]
|
||||
)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# Settings category determined from path
|
||||
# - usually path is './<category>/plugins/publish/<plugin file>'
|
||||
|
|
@ -386,9 +412,10 @@ def _get_plugin_settings(host_name, project_settings, plugin, log):
|
|||
|
||||
split_path = filepath.rsplit(os.path.sep, 5)
|
||||
if len(split_path) < 4:
|
||||
log.warning(
|
||||
'plugin path too short to extract host {}'.format(filepath)
|
||||
)
|
||||
log.debug((
|
||||
"Plugin path is too short to automatically"
|
||||
" extract settings category. {}"
|
||||
).format(filepath))
|
||||
return {}
|
||||
|
||||
category_from_file = split_path[-4]
|
||||
|
|
@ -410,6 +437,28 @@ def _get_plugin_settings(host_name, project_settings, plugin, log):
|
|||
return {}
|
||||
|
||||
|
||||
def apply_plugin_settings_automatically(plugin, settings, logger=None):
|
||||
"""Automatically apply plugin settings to a plugin object.
|
||||
|
||||
Note:
|
||||
This function was created to be able to use it in custom overrides of
|
||||
'apply_settings' class method.
|
||||
|
||||
Args:
|
||||
plugin (type[pyblish.api.Plugin]): Class of a plugin.
|
||||
settings (dict[str, Any]): Plugin specific settings.
|
||||
logger (Optional[logging.Logger]): Logger to log debug messages about
|
||||
applied settings values.
|
||||
"""
|
||||
|
||||
for option, value in settings.items():
|
||||
if logger:
|
||||
logger.debug("Plugin {} - Attr: {} -> {}".format(
|
||||
option, value, plugin.__name__
|
||||
))
|
||||
setattr(plugin, option, value)
|
||||
|
||||
|
||||
def filter_pyblish_plugins(plugins):
|
||||
"""Pyblish plugin filter which applies OpenPype settings.
|
||||
|
||||
|
|
@ -453,13 +502,10 @@ def filter_pyblish_plugins(plugins):
|
|||
)
|
||||
else:
|
||||
# Automated
|
||||
plugin_settins = _get_plugin_settings(
|
||||
host_name, project_settings, plugin, log
|
||||
plugin_settins = get_plugin_settings(
|
||||
plugin, project_settings, log, host_name
|
||||
)
|
||||
for option, value in plugin_settins.items():
|
||||
log.info("setting {}:{} on plugin {}".format(
|
||||
option, value, plugin.__name__))
|
||||
setattr(plugin, option, value)
|
||||
apply_plugin_settings_automatically(plugin, plugin_settins, log)
|
||||
|
||||
# Remove disabled plugins
|
||||
if getattr(plugin, "enabled", True) is False:
|
||||
|
|
|
|||
|
|
@ -506,6 +506,67 @@ or the scene file was copy pasted from different context.
|
|||
#### *Known errors*
|
||||
When there is a known error that can't be fixed by the user (e.g. can't connect to deadline service, etc.) `KnownPublishError` should be raised. The only difference is that its message is shown in UI to the artist otherwise a neutral message without context is shown.
|
||||
|
||||
### Plugins
|
||||
Plugin is a single processing unit that can work with publish context and instances.
|
||||
|
||||
#### Plugin types
|
||||
There are 2 types of plugins - `InstancePlugin` and `ContextPlugin`. Be aware that inheritance of plugin from `InstancePlugin` or `ContextPlugin` actually does not affect if plugin is instance or context plugin, that is affected by argument name in `process` method.
|
||||
|
||||
```python
|
||||
import pyblish.api
|
||||
|
||||
|
||||
# Context plugin
|
||||
class MyContextPlugin(pyblish.api.ContextPlugin):
|
||||
def process(self, context):
|
||||
...
|
||||
|
||||
# Instance plugin
|
||||
class MyInstancePlugin(pyblish.api.InstancePlugin):
|
||||
def process(self, instance):
|
||||
...
|
||||
|
||||
# Still an instance plugin
|
||||
class MyOtherInstancePlugin(pyblish.api.ContextPlugin):
|
||||
def process(self, instance):
|
||||
...
|
||||
```
|
||||
|
||||
#### Plugin filtering
|
||||
By pyblish logic, plugins have predefined filtering class attributes `hosts`, `targets` and `families`. Filter by `hosts` and `targets` are filters that are applied for current publishing process. Both filters are registered in `pyblish` module, `hosts` filtering may not match OpenPype host name (e.g. farm publishing uses `shell` in pyblish). Filter `families` works only on instance plugins and is dynamic during publish process by changing families of an instance.
|
||||
|
||||
All filters are list of a strings `families = ["image"]`. Empty list is invalid filter and plugin will be skipped, to allow plugin for all values use a start `families = ["*"]`. For more detailed filtering options check [pyblish documentation](https://api.pyblish.com/pluginsystem).
|
||||
|
||||
Each plugin must have order, there are 4 order milestones - Collect, Validate, Extract, Integration. Any plugin below collection order won't be processed. for more details check [pyblish documentation](https://api.pyblish.com/ordering).
|
||||
|
||||
#### Plugin settings
|
||||
Pyblish plugins may have settings. There are 2 ways how settings are applied, first is automated, and it's logic is based on function `filter_pyblish_plugins` in `./openpype/pipeline/publish/lib.py`, second is explicit by implementing class method `apply_settings` on a plugin.
|
||||
|
||||
|
||||
Automated logic is expecting specific structure of project settings `project_settings[{category}]["plugins"]["publish"][{plugin class name}]`. The category is a key in root of project settings. There are currently 3 ways how the category key is received.
|
||||
1. Use `settings_category` class attribute value from plugin. If `settings_category` is not `None` there is not any fallback to other way.
|
||||
2. Use currently registered pyblish host. This will be probably deprecated soon.
|
||||
3. Use 3rd folder name from a plugin filepath. From path `./maya/plugins/publish/collect_render.py` is used `maya` as the key.
|
||||
|
||||
For any other use-case is recommended to use explicit approach by implementing `apply_settings` method. Must use `@classmethod` decorator and expect arguments for project settings and system settings. We're planning to support single argument with only project settings.
|
||||
```python
|
||||
import pyblish.api
|
||||
|
||||
|
||||
class MyPlugin(pyblish.api.InstancePlugin):
|
||||
profiles = []
|
||||
|
||||
@classmethod
|
||||
def apply_settings(cls, project_settings, system_settings):
|
||||
cls.profiles = (
|
||||
project_settings
|
||||
["addon"]
|
||||
["plugins"]
|
||||
["publish"]
|
||||
["vfx_profiles"]
|
||||
)
|
||||
```
|
||||
|
||||
### Plugin extension
|
||||
Publish plugins can be extended by additional logic when inheriting from `OpenPypePyblishPluginMixin` which can be used as mixin (additional inheritance of class). Publish plugins that inherit from this mixin can define attributes that will be shown in **CreatedInstance**. One of the most important usages is to be able turn on/off optional plugins.
|
||||
|
||||
|
|
@ -596,4 +657,4 @@ Publish attributes work the same way as create attributes but the source of attr
|
|||
|
||||
### Create dialog
|
||||

|
||||
Create dialog is used by artist to create new instances in a context. The context selection can be enabled/disabled by changing `create_allow_context_change` on [creator plugin](#creator). In the middle part the artist selects what will be created and what variant it is. On the right side is information about the selected creator and its pre-create attributes. There is also a question mark button which extends the window and displays more detailed information about the creator.
|
||||
Create dialog is used by artist to create new instances in a context. The context selection can be enabled/disabled by changing `create_allow_context_change` on [creator plugin](#creator). In the middle part the artist selects what will be created and what variant it is. On the right side is information about the selected creator and its pre-create attributes. There is also a question mark button which extends the window and displays more detailed information about the creator.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue