From 59e12cc7c3cd451d0c0d0845502d1ce6bb155c51 Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Sat, 18 Jul 2015 08:42:01 +0200 Subject: [PATCH 1/8] Updating test to account for #210 --- tests/test_logic.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/test_logic.py b/tests/test_logic.py index 4a000a18..fd28f09b 100644 --- a/tests/test_logic.py +++ b/tests/test_logic.py @@ -316,6 +316,12 @@ def test_decrementing_order(): count = {"#": 0} + class MyDecrementingSelector(pyblish.api.Selector): + order = pyblish.api.Selector.order - 0.3 + + def process(self): + count["#"] += 0.1 + class MySelector(pyblish.api.Selector): def process(self, context): count["#"] += 1 @@ -349,8 +355,13 @@ def process(self): count["#"] += 10000 assert False, "I will not run" - for plugin in (MySelector, MyValidator, MyValidator2, MyExtractor): + for plugin in ( + MyDecrementingSelector, + MySelector, + MyValidator, + MyValidator2, + MyExtractor): pyblish.api.register_plugin(plugin) pyblish.util.publish() - assert_equals(count["#"], 111) + assert_equals(count["#"], 111.1) From 8bc371641bdeb395472397784cad80b158f94800 Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Sat, 18 Jul 2015 08:48:35 +0200 Subject: [PATCH 2/8] Updating Travis configuration --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f39fae2c..6255eb5e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,4 +18,5 @@ deploy: on: tags: true all_branches: true - python: 2.6 \ No newline at end of file + python: 2.6 +sudo: false \ No newline at end of file From 48b43f1c6292c86b194656ac3e38f5377945ebb9 Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Fri, 31 Jul 2015 20:40:08 +0200 Subject: [PATCH 3/8] Implemented #213 --- pyblish/plugin.py | 111 +++++++++++++++++++++++++++++-------------- tests/test_plugin.py | 24 ++++++++++ 2 files changed, 99 insertions(+), 36 deletions(-) diff --git a/pyblish/plugin.py b/pyblish/plugin.py index 610ce1b1..e21789d6 100644 --- a/pyblish/plugin.py +++ b/pyblish/plugin.py @@ -34,7 +34,15 @@ class Provider(object): - """Dependency provider""" + """Dependency provider + + This object is given a series of "services" that it then distributes + to a passed function based on the function's argument signature. + + For example, the function func:`myfunc(a, b)` is given the services + called "a" and "b", given they have previously been added to the provider. + + """ def __init__(self): self._services = dict() @@ -145,53 +153,84 @@ def load(self): return True -class MetaPlugin(type): - """Rewrite plug-ins written prior to 1.1 +def evaluate_pre11(plugin): + """Determine whether the plug-in is pre-1.1""" + plugin.__pre11__ = False - ..warning:: In case of plug-ins written prior to 1.1, - that also process both instance and context, - only the instance process will remain available. + if hasattr(plugin, "process_context"): + plugin.__pre11__ = True + plugin.process = plugin.process_context + del(plugin.process_context) - """ + if hasattr(plugin, "process_instance"): + plugin.__pre11__ = True + plugin.process = plugin.process_instance + del(plugin.process_instance) - def __init__(cls, *args, **kwargs): - cls.__pre11__ = False - cls.__contextEnabled__ = False - cls.__instanceEnabled__ = False + # Repair is deprecated + if hasattr(plugin, "repair_context"): + plugin.__pre11__ = True + plugin.repair = plugin.repair_context + del(plugin.repair_context) + + if hasattr(plugin, "repair_instance"): + plugin.__pre11__ = True + plugin.repair = plugin.repair_instance + del(plugin.repair_instance) - if hasattr(cls, "process_context"): - cls.__pre11__ = True - cls.process = cls.process_context - del(cls.process_context) - if hasattr(cls, "process_instance"): - cls.__pre11__ = True - cls.process = cls.process_instance - del(cls.process_instance) +def evaluate_enabledness(plugin): + """Deterimine whether the plug-in supports Context/Instance""" + plugin.__contextEnabled__ = False + plugin.__instanceEnabled__ = False - # Repair is deprecated - if hasattr(cls, "repair_context"): - cls.__pre11__ = True - cls.repair = cls.repair_context - del(cls.repair_context) + args_ = inspect.getargspec(plugin.process).args - if hasattr(cls, "repair_instance"): - cls.__pre11__ = True - cls.repair = cls.repair_instance - del(cls.repair_instance) + if "instance" in args_: + plugin.__instanceEnabled__ = True - args_ = inspect.getargspec(cls.process).args + if "context" in args_: + plugin.__contextEnabled__ = True - if "instance" in args_: - cls.__instanceEnabled__ = True + # Forwards-compatibility with asset + if "asset" in args_: + plugin.__instanceEnabled__ = True - if "context" in args_: - cls.__contextEnabled__ = True - # Forwards-compatibility with asset - if "asset" in args_: - cls.__instanceEnabled__ = True +def append_logger(plugin): + """Append logger to plugin + + The logger will include a plug-in's final name, as defined + by the subclasser. For example, if a plug-in is defined, subclassing + :class:`Plugin`, it's given name will be present in log records. + + """ + module = plugin.__module__ + name = plugin.__name__ + + # Package name appended, for filtering of LogRecord instances + logname = "pyblish.%s.%s" % (module, name) + plugin.log = logging.getLogger(logname) + plugin.log.setLevel(logging.DEBUG) + + # All messages are handled by root-logger + plugin.log.propagate = True + + +class MetaPlugin(type): + """Rewrite plug-ins written prior to 1.1 + + ..warning:: In case of plug-ins written prior to 1.1, + that also process both instance and context, + only the instance process will remain available. + + """ + + def __init__(cls, *args, **kwargs): + append_logger(cls) + evaluate_pre11(cls) + evaluate_enabledness(cls) return super(MetaPlugin, cls).__init__(*args, **kwargs) diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 5ea98bcc..dee9b150 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -197,3 +197,27 @@ class NotDiscoverable(pyblish.api.Plugin): plugins = [p.__name__ for p in pyblish.api.discover()] assert "Discoverable" in plugins assert "NotDiscoverable" not in plugins + + +@with_setup(lib.setup_empty, lib.teardown) +def test_unique_logger(): + """A unique logger is applied to every plug-in""" + + count = {"#": 0} + + class MyPlugin(pyblish.api.Plugin): + def process(self, context): + self.log.debug("Hello world") + count["#"] += 1 + + pyblish.api.register_plugin(MyPlugin) + + context = pyblish.util.publish() + + assert_equals(count["#"], 1) + print context.data("results") + + results = context.data("results")[0] + records = results["records"] + hello_world = records[0] + assert_equals(hello_world.msg, "Hello world") From b4618355d4fa1c9bf0bbc728e59fff469f155090 Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Mon, 3 Aug 2015 09:06:03 +0100 Subject: [PATCH 4/8] Adding default value to pyblish.lib.inrange --- pyblish/lib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyblish/lib.py b/pyblish/lib.py index 22fd4933..670ecb0c 100644 --- a/pyblish/lib.py +++ b/pyblish/lib.py @@ -10,7 +10,7 @@ 'LPT1', 'LPT2', 'LPT3', 'PRN', 'NUL') -def inrange(number, base, offset=0): +def inrange(number, base, offset=0.5): r"""Evaluate whether `number` is within `base` +- `offset` Lower bound is *included* whereas upper bound is *excluded* @@ -39,7 +39,7 @@ def inrange(number, base, offset=0): """ - return base - offset <= number < base + offset + return (base - offset) <= number < (base + offset) class MessageHandler(logging.Handler): From 56c55c5e19365dc347f899114dd7a9db94237354 Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Tue, 4 Aug 2015 13:50:13 +0100 Subject: [PATCH 5/8] Reducing code complexity In compliance with the recent support for @log-less plug-ins (#213) --- pyblish/plugins/collect_current_date.py | 4 ---- pyblish/plugins/collect_current_user.py | 4 ---- pyblish/plugins/collect_current_working_directory.py | 4 ---- 3 files changed, 12 deletions(-) diff --git a/pyblish/plugins/collect_current_date.py b/pyblish/plugins/collect_current_date.py index fd0a3fbb..8e009356 100644 --- a/pyblish/plugins/collect_current_date.py +++ b/pyblish/plugins/collect_current_date.py @@ -3,13 +3,9 @@ import pyblish.lib -@pyblish.api.log class CollectCurrentDate(pyblish.api.Collector): """Inject the current time into the Context""" - hosts = ['*'] - version = (0, 1, 0) - def process(self, context): """Formatting is coming from configuration""" date = pyblish.lib.time() diff --git a/pyblish/plugins/collect_current_user.py b/pyblish/plugins/collect_current_user.py index 66d915b5..6275cb60 100644 --- a/pyblish/plugins/collect_current_user.py +++ b/pyblish/plugins/collect_current_user.py @@ -3,12 +3,8 @@ import pyblish.api -@pyblish.api.log class CollectCurrentUser(pyblish.api.Collector): """Inject the currently logged on user into the Context""" - hosts = ['*'] - version = (0, 1, 0) - def process(self, context): context.set_data('user', value=getpass.getuser()) diff --git a/pyblish/plugins/collect_current_working_directory.py b/pyblish/plugins/collect_current_working_directory.py index f1454d04..2a93c937 100644 --- a/pyblish/plugins/collect_current_working_directory.py +++ b/pyblish/plugins/collect_current_working_directory.py @@ -3,12 +3,8 @@ import pyblish.api -@pyblish.api.log class CollectCurrentWorkingDirectory(pyblish.api.Collector): """Inject the current working directory into Context""" - hosts = ['*'] - version = (0, 1, 0) - def process(self, context): context.set_data('cwd', value=os.getcwd()) From d29c92a294e7afbd62ead41a933afb3248dda686 Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Tue, 4 Aug 2015 16:11:55 +0100 Subject: [PATCH 6/8] Added Context.__contains__ --- pyblish/plugin.py | 32 +++++++++++++++++++++++++++----- tests/test_context.py | 9 +++++++++ tests/test_di.py | 3 +-- tests/test_logic.py | 20 ++++++++++---------- 4 files changed, 47 insertions(+), 17 deletions(-) diff --git a/pyblish/plugin.py b/pyblish/plugin.py index e21789d6..daa3c8fc 100644 --- a/pyblish/plugin.py +++ b/pyblish/plugin.py @@ -475,8 +475,7 @@ def add(self, other): """ - if other not in self: - return self.append(other) + return self.append(other) def remove(self, other): """Remove member from self @@ -545,6 +544,28 @@ class Context(AbstractEntity): def id(self): return "Context" + def __contains__(self, key): + """Support both Instance objects and `id` strings + + Example: + >>> context = Context() + >>> instance = context.create_instance("MyInstance") + >>> "MyInstance" in context + True + >>> instance in context + True + >>> "NotExists" in context + False + + """ + + try: + key = key.id + except: + pass + + return key in self._children + def __init__(self, *args, **kwargs): super(Context, self).__init__(*args, **kwargs) @@ -613,16 +634,17 @@ class Instance(AbstractEntity): :class:`Context.create_instance()`. Attributes: - name (str): Name of instance, used in plugins + id (str): Unique identifier of instance + name (str): Name of instance parent (AbstractEntity): Optional parent of instance """ def __eq__(self, other): - return self.name == getattr(other, "name", None) + return self.id == getattr(other, "id", None) def __ne__(self, other): - return self.name != getattr(other, "name", None) + return self.id != getattr(other, "id", None) def __repr__(self): return u"%s.%s(\"%s\")" % (__name__, type(self).__name__, self) diff --git a/tests/test_context.py b/tests/test_context.py index 8ac04074..6910d4da 100644 --- a/tests/test_context.py +++ b/tests/test_context.py @@ -71,5 +71,14 @@ def test_context_itemgetter(): assert context[1].name == "MyInstanceB" +def test_in(): + """Querying whether an Instance is in a Context works""" + + context = pyblish.api.Context() + context.create_instance("MyInstance") + assert "MyInstance" in context + assert "NotExist" not in context + + if __name__ == '__main__': test_add_remove_instances() diff --git a/tests/test_di.py b/tests/test_di.py index a34a3b8a..0937de90 100644 --- a/tests/test_di.py +++ b/tests/test_di.py @@ -313,7 +313,6 @@ def process(self, context): context.create_asset(name, family="myFamily") count["#"] += 1 - class ValidateColor(pyblish.api.Validator): """Called twice""" families = ["myFamily"] @@ -363,4 +362,4 @@ def listRelatives(self, node): assert_equals(result["error"], None) assert_equals(len(instances), 2) - assert_equals(instances, ["bobby_char", "rocket_char"]) \ No newline at end of file + assert_equals(instances, ["bobby_char", "rocket_char"]) diff --git a/tests/test_logic.py b/tests/test_logic.py index fd28f09b..89dfd641 100644 --- a/tests/test_logic.py +++ b/tests/test_logic.py @@ -22,23 +22,21 @@ def process(self, context): class ValidateInstance(pyblish.api.Validator): def process(self, instance): - count["#"] += 1 + count["#"] += 10 assert False, "I was programmed to fail" class ExtractInstance(pyblish.api.Extractor): def process(self, instance): - count["#"] += 1 + count["#"] += 100 pyblish.api.register_plugin(SelectInstance) pyblish.api.register_plugin(ValidateInstance) pyblish.api.register_plugin(ExtractInstance) - _context = pyblish.plugin.Context() - for result in pyblish.logic.process( func=pyblish.plugin.process, plugins=pyblish.plugin.discover(), - context=_context): + context=pyblish.plugin.Context()): if isinstance(result, pyblish.logic.TestFailed): break @@ -46,17 +44,19 @@ def process(self, instance): if isinstance(result, Exception): assert False # This would be a bug - assert_equals(count["#"], 2) + assert_equals(count["#"], 11) + + context = pyblish.plugin.Context() - def context(): - return _context + def _context(): + return context count["#"] = 0 for result in pyblish.logic.process( func=pyblish.plugin.process, plugins=pyblish.plugin.discover, # <- Callable - context=context): # <- Callable + context=_context): # <- Callable if isinstance(result, pyblish.logic.TestFailed): break @@ -64,7 +64,7 @@ def context(): if isinstance(result, Exception): assert False # This would be a bug - assert_equals(count["#"], 2) + assert_equals(count["#"], 11) @with_setup(lib.setup_empty, lib.teardown) From c6e9225b25c6c96f4d04185d7dec828e432ee8de Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Tue, 4 Aug 2015 16:12:23 +0100 Subject: [PATCH 7/8] Added alias pyblish.util.run and establishing logger --- pyblish/util.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyblish/util.py b/pyblish/util.py index 9682c568..08c0e9af 100644 --- a/pyblish/util.py +++ b/pyblish/util.py @@ -26,7 +26,7 @@ import pyblish.logic import pyblish.plugin -log = logging.getLogger("pyblish") +log = pyblish.lib.setup_log(level=logging.ERROR) def publish(context=None, plugins=None, **kwargs): @@ -101,6 +101,7 @@ def conform(*args, **kwargs): collect = select integrate = conform +run = publish # Alias def _convenience(order, *args, **kwargs): From b7711606ba0e151ace438892e5275399806c458e Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Tue, 4 Aug 2015 16:12:28 +0100 Subject: [PATCH 8/8] Version bump --- CHANGES | 7 +++++++ pyblish/version.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 87ade3ab..af674136 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,13 @@ pyblish Changelog This contains all major version changes between pyblish releases. +Version 1.1.4 +------------- + +- Feature: Added support for `"MyInstance" in context` +- Enhancement: Removing the need for @pyblish.api.log (#213) +- Bugfix: Negative collectors (#210) + Version 1.1.3 ------------- diff --git a/pyblish/version.py b/pyblish/version.py index 811d33e8..a783a2e0 100644 --- a/pyblish/version.py +++ b/pyblish/version.py @@ -1,7 +1,7 @@ VERSION_MAJOR = 1 VERSION_MINOR = 1 -VERSION_PATCH = 3 +VERSION_PATCH = 4 version_info = (VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH) version = '%i.%i.%i' % version_info