diff --git a/pyblish/logic.py b/pyblish/logic.py index c00f6c94..130486b9 100644 --- a/pyblish/logic.py +++ b/pyblish/logic.py @@ -348,6 +348,12 @@ def Iterator(plugins, context, state=None): """ + # Run ContextPlugin only if instance of family is present when not "*" + # This is to preserve backwards compatility. + PYBLISH_CONTEXTPLUGIN_ON_FAMILY = bool( + os.getenv("PYBLISH_CONTEXTPLUGIN_ON_FAMILY") + ) + test = registered_test() state = state or { "nextOrder": None, @@ -381,4 +387,13 @@ def Iterator(plugins, context, state=None): yield plugin, instance else: + + if PYBLISH_CONTEXTPLUGIN_ON_FAMILY: + # When filtering to families at least a single instance with + # that family must be active in the current publish + if "*" not in plugin.families: + if not any(instance.data.get("publish") is not False + for instance in instances): + continue + yield plugin, None diff --git a/tests/lib.py b/tests/lib.py index 795a04be..385d794f 100644 --- a/tests/lib.py +++ b/tests/lib.py @@ -76,3 +76,18 @@ def tempdir(): yield tempdir finally: shutil.rmtree(tempdir) + + +@contextlib.contextmanager +def env_override(overrides): + """Temporarily override environment variables""" + assert isinstance(overrides, dict) + original = os.environ.copy() + os.environ.update(overrides) + + try: + yield + finally: + # Reset + os.environ.clear() + os.environ.update(original) diff --git a/tests/test_logic.py b/tests/test_logic.py index 710977cb..6b61abf7 100644 --- a/tests/test_logic.py +++ b/tests/test_logic.py @@ -67,6 +67,66 @@ def process(self, instance): assert count["#"] == 101, count +@with_setup(lib.setup, lib.teardown) +def test_contextplugin_on_family_iterator(): + """Iterator skips ContextPlugin filtered to family + + This functionality is only enabled when PYBLISH_CONTEXTPLUGIN_ON_FAMILY + environment variable is set to a True value to preserve backwards + compatibility. + + """ + + count = {"#": 0} + + class MyCollector(api.ContextPlugin): + order = api.CollectorOrder + + def process(self, context): + instance = context.create_instance("A1") + instance.data['families'] = ["A"] + instance = context.create_instance("A2") + instance.data['families'] = ["A"] + instance = context.create_instance("C1") + instance.data['families'] = ["C"] + + count["#"] += 1 + + class ValidateA(api.ContextPlugin): + families = ["A"] + order = api.CollectorOrder + + def process(self, context): + count["#"] += 10 + + class ValidateB(api.ContextPlugin): + families = ["B"] + order = api.CollectorOrder + + def process(self, context): + count["#"] += 100 + + class ValidateAC(api.ContextPlugin): + families = ["A", "C"] + order = api.CollectorOrder + + def process(self, context): + count["#"] += 1000 + + context = api.Context() + plugins = [MyCollector, ValidateA, ValidateB, ValidateAC] + + assert count["#"] == 0, count + + with lib.env_override({"PYBLISH_CONTEXTPLUGIN_ON_FAMILY": "True"}): + for Plugin, instance in logic.Iterator(plugins, context): + assert Plugin.__name__ != "ValidateB" + plugin.process(Plugin, context, instance) + + # Collector runs once, one Validator runs once + assert count["#"] == 1011, count + + def test_register_gui(): """Registering at run-time takes precedence over those from environment"""