Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

General: Plugin settings handled by plugins #3623

Merged
101 changes: 54 additions & 47 deletions openpype/lib/plugin_tools.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# -*- coding: utf-8 -*-
"""Avalon/Pyblish plugin tools."""
import os
import inspect
import logging
import re
import json

import warnings
import functools

from openpype.client import get_asset_by_id
from openpype.settings import get_project_settings

Expand All @@ -17,6 +19,51 @@
DEFAULT_SUBSET_TEMPLATE = "{family}{Variant}"


class PluginToolsDeprecatedWarning(DeprecationWarning):
pass


def deprecated(new_destination):
"""Mark functions as deprecated.

It will result in a warning being emitted when the function is used.
"""

func = None
if callable(new_destination):
func = new_destination
new_destination = None

def _decorator(decorated_func):
if new_destination is None:
warning_message = (
" Please check content of deprecated function to figure out"
" possible replacement."
)
else:
warning_message = " Please replace your usage with '{}'.".format(
new_destination
)

@functools.wraps(decorated_func)
def wrapper(*args, **kwargs):
warnings.simplefilter("always", PluginToolsDeprecatedWarning)
warnings.warn(
(
"Call to deprecated function '{}'"
"\nFunction was moved or removed.{}"
).format(decorated_func.__name__, warning_message),
category=PluginToolsDeprecatedWarning,
stacklevel=4
)
return decorated_func(*args, **kwargs)
return wrapper

if func is None:
return _decorator
return _decorator(func)


class TaskNotSetError(KeyError):
def __init__(self, msg=None):
if not msg:
Expand Down Expand Up @@ -197,6 +244,7 @@ def prepare_template_data(fill_pairs):
return fill_data


@deprecated("openpype.pipeline.publish.lib.filter_pyblish_plugins")
def filter_pyblish_plugins(plugins):
"""Filter pyblish plugins by presets.

Expand All @@ -206,57 +254,14 @@ def filter_pyblish_plugins(plugins):
Args:
plugins (dict): Dictionary of plugins produced by :mod:`pyblish-base`
`discover()` method.

"""
from pyblish import api

host = api.current_host()

presets = get_project_settings(os.environ['AVALON_PROJECT']) or {}
# skip if there are no presets to process
if not presets:
return

# iterate over plugins
for plugin in plugins[:]:
from openpype.pipeline.publish.lib import filter_pyblish_plugins

try:
config_data = presets[host]["publish"][plugin.__name__]
except KeyError:
# host determined from path
file = os.path.normpath(inspect.getsourcefile(plugin))
file = os.path.normpath(file)

split_path = file.split(os.path.sep)
if len(split_path) < 4:
log.warning(
'plugin path too short to extract host {}'.format(file)
)
continue

host_from_file = split_path[-4]
plugin_kind = split_path[-2]

# TODO: change after all plugins are moved one level up
if host_from_file == "openpype":
host_from_file = "global"

try:
config_data = presets[host_from_file][plugin_kind][plugin.__name__] # noqa: E501
except KeyError:
continue

for option, value in config_data.items():
if option == "enabled" and value is False:
log.info('removing plugin {}'.format(plugin.__name__))
plugins.remove(plugin)
else:
log.info('setting {}:{} on plugin {}'.format(
option, value, plugin.__name__))

setattr(plugin, option, value)
filter_pyblish_plugins(plugins)


@deprecated
def set_plugin_attributes_from_settings(
plugins, superclass, host_name=None, project_name=None
):
Expand All @@ -273,6 +278,8 @@ def set_plugin_attributes_from_settings(
project_name (str): Name of project for which settings will be loaded.
Value from environment `AVALON_PROJECT` is used if not entered.
"""

# Function is not used anymore
from openpype.pipeline import LegacyCreator, LoaderPlugin

# determine host application to use for finding presets
Expand Down
2 changes: 1 addition & 1 deletion openpype/pipeline/context_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
)
from openpype.modules import load_modules, ModulesManager
from openpype.settings import get_project_settings
from openpype.lib import filter_pyblish_plugins

from .publish.lib import filter_pyblish_plugins
from .anatomy import Anatomy
from .template_data import get_template_data_with_names
from . import (
Expand Down
25 changes: 20 additions & 5 deletions openpype/pipeline/create/creator_plugins.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
import copy

from abc import (
Expand All @@ -7,10 +8,8 @@
)
import six

from openpype.lib import (
get_subset_name_with_asset_doc,
set_plugin_attributes_from_settings,
)
from openpype.settings import get_system_settings, get_project_settings
from openpype.lib import get_subset_name_with_asset_doc
from openpype.pipeline.plugin_discover import (
discover,
register_plugin,
Expand Down Expand Up @@ -438,8 +437,24 @@ def discover_creator_plugins():


def discover_legacy_creator_plugins():
from openpype.lib import Logger

log = Logger.get_logger("CreatorDiscover")

plugins = discover(LegacyCreator)
set_plugin_attributes_from_settings(plugins, LegacyCreator)
project_name = os.environ.get("AVALON_PROJECT")
system_settings = get_system_settings()
project_settings = get_project_settings(project_name)
for plugin in plugins:
try:
plugin.apply_settings(project_settings, system_settings)
except Exception:
log.warning(
"Failed to apply settings to loader {}".format(
plugin.__name__
),
exc_info=True
)
return plugins


Expand Down
43 changes: 43 additions & 0 deletions openpype/pipeline/create/legacy_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- 'create' -> 'legacy_create'
"""

import os
import logging
import collections

Expand Down Expand Up @@ -37,6 +38,48 @@ def __init__(self, name, asset, options=None, data=None):

self.data.update(data or {})

@classmethod
def apply_settings(cls, project_settings, system_settings):
"""Apply OpenPype settings to a plugin class."""

host_name = os.environ.get("AVALON_APP")
plugin_type = "create"
plugin_type_settings = (
project_settings
.get(host_name, {})
.get(plugin_type, {})
)
global_type_settings = (
project_settings
.get("global", {})
.get(plugin_type, {})
)
if not global_type_settings and not plugin_type_settings:
return

plugin_name = cls.__name__

plugin_settings = None
# Look for plugin settings in host specific settings
if plugin_name in plugin_type_settings:
plugin_settings = plugin_type_settings[plugin_name]

# Look for plugin settings in global settings
elif plugin_name in global_type_settings:
plugin_settings = global_type_settings[plugin_name]

if not plugin_settings:
return

print(">>> We have preset for {}".format(plugin_name))
for option, value in plugin_settings.items():
if option == "enabled" and value is False:
setattr(cls, "active", False)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not call setattr with a constant attribute value, it is not any safer than normal property access.

print(" - is disabled by preset")
else:
setattr(cls, option, value)
print(" - setting `{}`: `{}`".format(option, value))

def process(self):
pass

Expand Down
64 changes: 61 additions & 3 deletions openpype/pipeline/load/plugins.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import os
import logging

from openpype.lib import set_plugin_attributes_from_settings
from openpype.settings import get_system_settings, get_project_settings
from openpype.pipeline import legacy_io
from openpype.pipeline.plugin_discover import (
discover,
register_plugin,
Expand Down Expand Up @@ -37,6 +39,46 @@ class LoaderPlugin(list):
def __init__(self, context):
self.fname = self.filepath_from_context(context)

@classmethod
def apply_settings(cls, project_settings, system_settings):
host_name = os.environ.get("AVALON_APP")
plugin_type = "load"
plugin_type_settings = (
project_settings
.get(host_name, {})
.get(plugin_type, {})
)
global_type_settings = (
project_settings
.get("global", {})
.get(plugin_type, {})
)
if not global_type_settings and not plugin_type_settings:
return

plugin_name = cls.__name__

plugin_settings = None
# Look for plugin settings in host specific settings
if plugin_name in plugin_type_settings:
plugin_settings = plugin_type_settings[plugin_name]

# Look for plugin settings in global settings
elif plugin_name in global_type_settings:
plugin_settings = global_type_settings[plugin_name]

if not plugin_settings:
return

print(">>> We have preset for {}".format(plugin_name))
for option, value in plugin_settings.items():
if option == "enabled" and value is False:
setattr(cls, "active", False)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not call setattr with a constant attribute value, it is not any safer than normal property access.

print(" - is disabled by preset")
else:
setattr(cls, option, value)
print(" - setting `{}`: `{}`".format(option, value))

@classmethod
def get_representations(cls):
return cls.representations
Expand Down Expand Up @@ -110,9 +152,25 @@ def __init__(self, context):
pass


def discover_loader_plugins():
def discover_loader_plugins(project_name=None):
from openpype.lib import Logger

log = Logger.get_logger("LoaderDiscover")
plugins = discover(LoaderPlugin)
set_plugin_attributes_from_settings(plugins, LoaderPlugin)
if not project_name:
project_name = legacy_io.active_project()
system_settings = get_system_settings()
project_settings = get_project_settings(project_name)
for plugin in plugins:
try:
plugin.apply_settings(project_settings, system_settings)
except Exception:
log.warning(
"Failed to apply settings to loader {}".format(
plugin.__name__
),
exc_info=True
)
return plugins


Expand Down
Loading