diff --git a/.gitignore b/.gitignore index baf7b918e2..801760201e 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,18 @@ __pycache__/ # Editor backup files # ####################### *~ + +# Unit test / coverage reports +############################## +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +/coverage +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ diff --git a/pype/.coveragerc b/pype/.coveragerc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pype/__init__.py b/pype/__init__.py index 44721c3eaf..db77a58cd2 100644 --- a/pype/__init__.py +++ b/pype/__init__.py @@ -2,6 +2,7 @@ import os from pyblish import api as pyblish from avalon import api as avalon +from .lib import filter_pyblish_plugins import logging log = logging.getLogger(__name__) @@ -22,10 +23,12 @@ LOAD_PATH = os.path.join(PLUGINS_DIR, "global", "load") def install(): log.info("Registering global plug-ins..") pyblish.register_plugin_path(PUBLISH_PATH) + pyblish.register_discovery_filter(filter_pyblish_plugins) avalon.register_plugin_path(avalon.Loader, LOAD_PATH) def uninstall(): log.info("Deregistering global plug-ins..") pyblish.deregister_plugin_path(PUBLISH_PATH) + pyblish.deregister_discovery_filter(filter_pyblish_plugins) avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH) log.info("Global plug-ins unregistred") diff --git a/pype/lib.py b/pype/lib.py index 648a26a8a3..e163cc14fc 100644 --- a/pype/lib.py +++ b/pype/lib.py @@ -478,3 +478,35 @@ def get_presets_path(): path_items = [templates, 'presets'] filepath = os.path.sep.join(path_items) return filepath + + +def filter_pyblish_plugins(plugins): + """ + This servers as plugin filter / modifier for pyblish. It will load plugin + definitions from presets and filter those needed to be excluded. + + :param plugins: Dictionary of plugins produced by :mod:`pyblish-base` + `discover()` method. + :type plugins: Dict + """ + from pypeapp import config + from pyblish import api + + host = api.current_host() + + # iterate over plugins + for plugin in plugins[:]: + try: + config_data = config.get_presets()['plugins'][host]["publish"][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) diff --git a/pype/tests/__init__.py b/pype/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pype/tests/lib.py b/pype/tests/lib.py new file mode 100644 index 0000000000..85b9032836 --- /dev/null +++ b/pype/tests/lib.py @@ -0,0 +1,80 @@ +import os +import sys +import shutil +import tempfile +import contextlib + +import pyblish +import pyblish.cli +import pyblish.plugin +from pyblish.vendor import six + + +# Setup +HOST = 'python' +FAMILY = 'test.family' + +REGISTERED = pyblish.plugin.registered_paths() +PACKAGEPATH = pyblish.lib.main_package_path() +ENVIRONMENT = os.environ.get("PYBLISHPLUGINPATH", "") +PLUGINPATH = os.path.join(PACKAGEPATH, '..', 'tests', 'plugins') + + +def setup(): + pyblish.plugin.deregister_all_paths() + + +def setup_empty(): + """Disable all plug-ins""" + setup() + pyblish.plugin.deregister_all_plugins() + pyblish.plugin.deregister_all_paths() + pyblish.plugin.deregister_all_hosts() + pyblish.plugin.deregister_all_callbacks() + pyblish.plugin.deregister_all_targets() + pyblish.api.deregister_all_discovery_filters() + + +def teardown(): + """Restore previously REGISTERED paths""" + + pyblish.plugin.deregister_all_paths() + for path in REGISTERED: + pyblish.plugin.register_plugin_path(path) + + os.environ["PYBLISHPLUGINPATH"] = ENVIRONMENT + pyblish.api.deregister_all_plugins() + pyblish.api.deregister_all_hosts() + pyblish.api.deregister_all_discovery_filters() + pyblish.api.deregister_test() + pyblish.api.__init__() + + +@contextlib.contextmanager +def captured_stdout(): + """Temporarily reassign stdout to a local variable""" + try: + sys.stdout = six.StringIO() + yield sys.stdout + finally: + sys.stdout = sys.__stdout__ + + +@contextlib.contextmanager +def captured_stderr(): + """Temporarily reassign stderr to a local variable""" + try: + sys.stderr = six.StringIO() + yield sys.stderr + finally: + sys.stderr = sys.__stderr__ + + +@contextlib.contextmanager +def tempdir(): + """Provide path to temporary directory""" + try: + tempdir = tempfile.mkdtemp() + yield tempdir + finally: + shutil.rmtree(tempdir) diff --git a/pype/tests/test_pyblish_filter.py b/pype/tests/test_pyblish_filter.py new file mode 100644 index 0000000000..8d747e63df --- /dev/null +++ b/pype/tests/test_pyblish_filter.py @@ -0,0 +1,60 @@ +from . import lib +import pyblish.api +import pyblish.util +import pyblish.plugin +from pype.lib import filter_pyblish_plugins +import os + + +def test_pyblish_plugin_filter_modifier(printer, monkeypatch): + """ + Test if pyblish filter can filter and modify plugins on-the-fly. + """ + + lib.setup_empty() + monkeypatch.setitem(os.environ, 'PYBLISHPLUGINPATH', '') + plugins = pyblish.api.registered_plugins() + printer("Test if we have no registered plugins") + assert len(plugins) == 0 + paths = pyblish.api.registered_paths() + printer("Test if we have no registered plugin paths") + print(paths) + + class MyTestPlugin(pyblish.api.InstancePlugin): + my_test_property = 1 + label = "Collect Renderable Camera(s)" + hosts = ["test"] + families = ["default"] + + pyblish.api.register_host("test") + pyblish.api.register_plugin(MyTestPlugin) + pyblish.api.register_discovery_filter(filter_pyblish_plugins) + plugins = pyblish.api.discover() + + printer("Test if only one plugin was discovered") + assert len(plugins) == 1 + printer("Test if properties are modified correctly") + assert plugins[0].label == "loaded from preset" + assert plugins[0].families == ["changed", "by", "preset"] + assert plugins[0].optional is True + + lib.teardown() + + +def test_pyblish_plugin_filter_removal(monkeypatch): + """ Test that plugin can be removed by filter """ + lib.setup_empty() + monkeypatch.setitem(os.environ, 'PYBLISHPLUGINPATH', '') + plugins = pyblish.api.registered_plugins() + + class MyTestRemovedPlugin(pyblish.api.InstancePlugin): + my_test_property = 1 + label = "Collect Renderable Camera(s)" + hosts = ["test"] + families = ["default"] + + pyblish.api.register_host("test") + pyblish.api.register_plugin(MyTestRemovedPlugin) + pyblish.api.register_discovery_filter(filter_pyblish_plugins) + plugins = pyblish.api.discover() + assert len(plugins) == 0