![](https://seccdn.libravatar.org/avatar/e2145bc5cf53dda95c308a3c75e8fef3.jpg?s=120&d=mm&r=g)
Hello community, here is the log from the commit of package python-pluggy for openSUSE:Factory checked in at 2017-12-02 13:10:45 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pluggy (Old) and /work/SRC/openSUSE:Factory/.python-pluggy.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "python-pluggy" Sat Dec 2 13:10:45 2017 rev:4 rq:545892 version:0.6.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-pluggy/python-pluggy.changes 2017-11-12 18:00:04.321789400 +0100 +++ /work/SRC/openSUSE:Factory/.python-pluggy.new/python-pluggy.changes 2017-12-02 13:10:47.838095674 +0100 @@ -1,0 +2,18 @@ +Sun Nov 26 21:25:17 UTC 2017 - arun@gmx.de + +- update to version 0.6.0 + * Add CI testing for the features, release, and master branches of + pytest (PR #79). + * Document public API for _Result objects passed to wrappers (PR + #85). + * Document and test hook LIFO ordering (PR #85). + * Turn warnings into errors in test suite (PR #89). + * Deprecate _Result.result (PR #88). + * Convert _Multicall to a simple function distinguishing it from the + legacy version (PR #90). + * Resolve E741 errors (PR #96). + * Test and bug fix for unmarked hook collection (PRs #97 and #102). + * Drop support for EOL Python 2.6 and 3.3 (PR #103). + * Fix inspect based arg introspection on py3.6 (PR #94). + +------------------------------------------------------------------- Old: ---- pluggy-0.5.2.tar.gz New: ---- pluggy-0.6.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pluggy.spec ++++++ --- /var/tmp/diff_new_pack.jsSx5Q/_old 2017-12-02 13:10:48.414074694 +0100 +++ /var/tmp/diff_new_pack.jsSx5Q/_new 2017-12-02 13:10:48.418074548 +0100 @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-pluggy -Version: 0.5.2 +Version: 0.6.0 Release: 0 Summary: Plugin registration and hook calling mechanisms for Python License: MIT ++++++ pluggy-0.5.2.tar.gz -> pluggy-0.6.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluggy-0.5.2/PKG-INFO new/pluggy-0.6.0/PKG-INFO --- old/pluggy-0.5.2/PKG-INFO 2017-09-06 15:53:22.000000000 +0200 +++ new/pluggy-0.6.0/PKG-INFO 2017-11-24 17:32:29.000000000 +0100 @@ -1,11 +1,12 @@ -Metadata-Version: 1.1 +Metadata-Version: 1.2 Name: pluggy -Version: 0.5.2 +Version: 0.6.0 Summary: plugin and hook calling mechanisms for python Home-page: https://github.com/pytest-dev/pluggy Author: Holger Krekel Author-email: holger@merlinux.eu License: MIT license +Description-Content-Type: UNKNOWN Description: pluggy - A minimalist production ready plugin system ==================================================== |pypi| |anaconda| |versions| |travis| |appveyor| @@ -103,10 +104,9 @@ Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluggy-0.5.2/pluggy/__init__.py new/pluggy-0.6.0/pluggy/__init__.py --- old/pluggy-0.5.2/pluggy/__init__.py 2017-09-06 15:52:39.000000000 +0200 +++ new/pluggy-0.6.0/pluggy/__init__.py 2017-11-24 17:31:26.000000000 +0100 @@ -1,8 +1,8 @@ import inspect import warnings -from .callers import _MultiCall, HookCallError, _raise_wrapfail, _Result +from .callers import _multicall, HookCallError, _Result, _legacymulticall -__version__ = '0.5.2' +__version__ = '0.6.0' __all__ = ["PluginManager", "PluginValidationError", "HookCallError", "HookspecMarker", "HookimplMarker"] @@ -166,25 +166,6 @@ return self.__class__(self.root, self.tags + (name,)) -def _wrapped_call(wrap_controller, func): - """ Wrap calling to a function with a generator which needs to yield - exactly once. The yield point will trigger calling the wrapped function - and return its ``_Result`` to the yield point. The generator then needs - to finish (raise StopIteration) in order for the wrapped call to complete. - """ - try: - next(wrap_controller) # first yield - except StopIteration: - _raise_wrapfail(wrap_controller, "did not yield") - call_outcome = _Result.from_call(func) - try: - wrap_controller.send(call_outcome) - _raise_wrapfail(wrap_controller, "has second yield") - except StopIteration: - pass - return call_outcome.get_result() - - class _TracedHookExecution(object): def __init__(self, pluginmanager, before, after): self.pluginmanager = pluginmanager @@ -231,8 +212,9 @@ self._implprefix = implprefix self._inner_hookexec = lambda hook, methods, kwargs: \ hook.multicall( - methods, kwargs, specopts=hook.spec_opts, hook=hook - ).execute() + methods, kwargs, + firstresult=hook.spec_opts.get('firstresult'), + ) def _hookexec(self, hook, methods, kwargs): # called from all hookcaller instances. @@ -460,7 +442,7 @@ def after(outcome, hook_name, methods, kwargs): if outcome.excinfo is None: - hooktrace("finish", hook_name, "-->", outcome.result) + hooktrace("finish", hook_name, "-->", outcome.get_result()) hooktrace.root.indent -= 1 return self.add_hookcall_monitoring(before, after) @@ -485,54 +467,6 @@ return orig -class _LegacyMultiCall(object): - """ execute a call into multiple python functions/methods. """ - - # XXX note that the __multicall__ argument is supported only - # for pytest compatibility reasons. It was never officially - # supported there and is explicitely deprecated since 2.8 - # so we can remove it soon, allowing to avoid the below recursion - # in execute() and simplify/speed up the execute loop. - - def __init__(self, hook_impls, kwargs, specopts={}, hook=None): - self.hook = hook - self.hook_impls = hook_impls - self.caller_kwargs = kwargs # come from _HookCaller.__call__() - self.caller_kwargs["__multicall__"] = self - self.specopts = hook.spec_opts if hook else specopts - - def execute(self): - caller_kwargs = self.caller_kwargs - self.results = results = [] - firstresult = self.specopts.get("firstresult") - - while self.hook_impls: - hook_impl = self.hook_impls.pop() - try: - args = [caller_kwargs[argname] for argname in hook_impl.argnames] - except KeyError: - for argname in hook_impl.argnames: - if argname not in caller_kwargs: - raise HookCallError( - "hook call must provide argument %r" % (argname,)) - if hook_impl.hookwrapper: - return _wrapped_call(hook_impl.function(*args), self.execute) - res = hook_impl.function(*args) - if res is not None: - if firstresult: - return res - results.append(res) - - if not firstresult: - return results - - def __repr__(self): - status = "%d meths" % (len(self.hook_impls),) - if hasattr(self, "results"): - status = ("%d results, " % len(self.results)) + status - return "<_MultiCall %s, kwargs=%r>" % (status, self.caller_kwargs) - - def varnames(func): """Return tuple of positional and keywrord argument names for a function, method, class or callable. @@ -558,7 +492,7 @@ return () try: # func MUST be a function or method here or we won't parse any args - spec = inspect.getargspec(func) + spec = _getargspec(func) except TypeError: return (), () @@ -595,20 +529,22 @@ class _HookCaller(object): - def __init__(self, name, hook_execute, specmodule_or_class=None, spec_opts=None): + def __init__(self, name, hook_execute, specmodule_or_class=None, + spec_opts=None): self.name = name self._wrappers = [] self._nonwrappers = [] self._hookexec = hook_execute + self._specmodule_or_class = None self.argnames = None self.kwargnames = None - self.multicall = _MultiCall + self.multicall = _multicall + self.spec_opts = spec_opts or {} if specmodule_or_class is not None: - assert spec_opts is not None self.set_specification(specmodule_or_class, spec_opts) def has_spec(self): - return hasattr(self, "_specmodule_or_class") + return self._specmodule_or_class is not None def set_specification(self, specmodule_or_class, spec_opts): assert not self.has_spec() @@ -617,7 +553,7 @@ # get spec arg signature argnames, self.kwargnames = varnames(specfunc) self.argnames = ["__multicall__"] + list(argnames) - self.spec_opts = spec_opts + self.spec_opts.update(spec_opts) if spec_opts.get("historic"): self._call_history = [] @@ -659,7 +595,7 @@ "removed in an upcoming release.", DeprecationWarning ) - self.multicall = _LegacyMultiCall + self.multicall = _legacymulticall def __repr__(self): return "<_HookCaller %r>" % (self.name,) @@ -673,9 +609,10 @@ kwargs.keys()) if notincall: warnings.warn( - "Argument(s) {0} which are declared in the hookspec " + "Argument(s) {} which are declared in the hookspec " "can not be found in this hook call" - .format(tuple(notincall)) + .format(tuple(notincall)), + stacklevel=2, ) return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs) @@ -725,6 +662,14 @@ self.__dict__.update(hook_impl_opts) +if hasattr(inspect, 'getfullargspec'): + def _getargspec(func): + return inspect.getfullargspec(func) +else: + def _getargspec(func): + return inspect.getargspec(func) + + if hasattr(inspect, 'signature'): def _formatdef(func): return "%s%s" % ( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluggy-0.5.2/pluggy/callers.py new/pluggy-0.6.0/pluggy/callers.py --- old/pluggy-0.5.2/pluggy/callers.py 2017-09-05 15:27:35.000000000 +0200 +++ new/pluggy-0.6.0/pluggy/callers.py 2017-11-24 14:37:36.000000000 +0100 @@ -2,7 +2,7 @@ Call loop machinery ''' import sys - +import warnings _py3 = sys.version_info > (3, 0) @@ -26,8 +26,19 @@ class _Result(object): def __init__(self, result, excinfo): - self.result = result - self.excinfo = excinfo + self._result = result + self._excinfo = excinfo + + @property + def excinfo(self): + return self._excinfo + + @property + def result(self): + """Get the result(s) for this hook call (DEPRECATED in favor of ``get_result()``).""" + msg = 'Use get_result() which forces correct exception handling' + warnings.warn(DeprecationWarning(msg), stacklevel=2) + return self._result @classmethod def from_call(cls, func): @@ -41,81 +52,150 @@ return cls(result, excinfo) def force_result(self, result): - self.result = result - self.excinfo = None + """Force the result(s) to ``result``. + + If the hook was marked as a ``firstresult`` a single value should + be set otherwise set a (modified) list of results. Any exceptions + found during invocation will be deleted. + """ + self._result = result + self._excinfo = None def get_result(self): + """Get the result(s) for this hook call. + + If the hook was marked as a ``firstresult`` only a single value + will be returned otherwise a list of results. + """ __tracebackhide__ = True - if self.excinfo is None: - return self.result + if self._excinfo is None: + return self._result else: - ex = self.excinfo + ex = self._excinfo if _py3: raise ex[1].with_traceback(ex[2]) _reraise(*ex) # noqa -class _MultiCall(object): - """Execute a call into multiple python functions/methods. +def _wrapped_call(wrap_controller, func): + """ Wrap calling to a function with a generator which needs to yield + exactly once. The yield point will trigger calling the wrapped function + and return its ``_Result`` to the yield point. The generator then needs + to finish (raise StopIteration) in order for the wrapped call to complete. """ - def __init__(self, hook_impls, kwargs, specopts={}, hook=None): - self.hook = hook + try: + next(wrap_controller) # first yield + except StopIteration: + _raise_wrapfail(wrap_controller, "did not yield") + call_outcome = _Result.from_call(func) + try: + wrap_controller.send(call_outcome) + _raise_wrapfail(wrap_controller, "has second yield") + except StopIteration: + pass + return call_outcome.get_result() + + +class _LegacyMultiCall(object): + """ execute a call into multiple python functions/methods. """ + + # XXX note that the __multicall__ argument is supported only + # for pytest compatibility reasons. It was never officially + # supported there and is explicitely deprecated since 2.8 + # so we can remove it soon, allowing to avoid the below recursion + # in execute() and simplify/speed up the execute loop. + + def __init__(self, hook_impls, kwargs, firstresult=False): self.hook_impls = hook_impls self.caller_kwargs = kwargs # come from _HookCaller.__call__() - self.specopts = hook.spec_opts if hook else specopts + self.caller_kwargs["__multicall__"] = self + self.firstresult = firstresult def execute(self): - __tracebackhide__ = True caller_kwargs = self.caller_kwargs self.results = results = [] - firstresult = self.specopts.get("firstresult") - excinfo = None - try: # run impl and wrapper setup functions in a loop - teardowns = [] - try: - for hook_impl in reversed(self.hook_impls): - try: - args = [caller_kwargs[argname] for argname in hook_impl.argnames] - # args = operator.itemgetter(hookimpl.argnames)(caller_kwargs) - except KeyError: - for argname in hook_impl.argnames: - if argname not in caller_kwargs: - raise HookCallError( - "hook call must provide argument %r" % (argname,)) - - if hook_impl.hookwrapper: - try: - gen = hook_impl.function(*args) - next(gen) # first yield - teardowns.append(gen) - except StopIteration: - _raise_wrapfail(gen, "did not yield") - else: - res = hook_impl.function(*args) - if res is not None: - results.append(res) - if firstresult: # halt further impl calls - break - except BaseException: - excinfo = sys.exc_info() - finally: - if firstresult: # first result hooks return a single value - outcome = _Result(results[0] if results else None, excinfo) - else: - outcome = _Result(results, excinfo) + firstresult = self.firstresult - # run all wrapper post-yield blocks - for gen in reversed(teardowns): - try: - gen.send(outcome) - _raise_wrapfail(gen, "has second yield") - except StopIteration: - pass + while self.hook_impls: + hook_impl = self.hook_impls.pop() + try: + args = [caller_kwargs[argname] for argname in hook_impl.argnames] + except KeyError: + for argname in hook_impl.argnames: + if argname not in caller_kwargs: + raise HookCallError( + "hook call must provide argument %r" % (argname,)) + if hook_impl.hookwrapper: + return _wrapped_call(hook_impl.function(*args), self.execute) + res = hook_impl.function(*args) + if res is not None: + if firstresult: + return res + results.append(res) - return outcome.get_result() + if not firstresult: + return results def __repr__(self): status = "%d meths" % (len(self.hook_impls),) if hasattr(self, "results"): status = ("%d results, " % len(self.results)) + status return "<_MultiCall %s, kwargs=%r>" % (status, self.caller_kwargs) + + +def _legacymulticall(hook_impls, caller_kwargs, firstresult=False): + return _LegacyMultiCall( + hook_impls, caller_kwargs, firstresult=firstresult).execute() + + +def _multicall(hook_impls, caller_kwargs, firstresult=False): + """Execute a call into multiple python functions/methods and return the + result(s). + + ``caller_kwargs`` comes from _HookCaller.__call__(). + """ + __tracebackhide__ = True + results = [] + excinfo = None + try: # run impl and wrapper setup functions in a loop + teardowns = [] + try: + for hook_impl in reversed(hook_impls): + try: + args = [caller_kwargs[argname] for argname in hook_impl.argnames] + except KeyError: + for argname in hook_impl.argnames: + if argname not in caller_kwargs: + raise HookCallError( + "hook call must provide argument %r" % (argname,)) + + if hook_impl.hookwrapper: + try: + gen = hook_impl.function(*args) + next(gen) # first yield + teardowns.append(gen) + except StopIteration: + _raise_wrapfail(gen, "did not yield") + else: + res = hook_impl.function(*args) + if res is not None: + results.append(res) + if firstresult: # halt further impl calls + break + except BaseException: + excinfo = sys.exc_info() + finally: + if firstresult: # first result hooks return a single value + outcome = _Result(results[0] if results else None, excinfo) + else: + outcome = _Result(results, excinfo) + + # run all wrapper post-yield blocks + for gen in reversed(teardowns): + try: + gen.send(outcome) + _raise_wrapfail(gen, "has second yield") + except StopIteration: + pass + + return outcome.get_result() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluggy-0.5.2/pluggy.egg-info/PKG-INFO new/pluggy-0.6.0/pluggy.egg-info/PKG-INFO --- old/pluggy-0.5.2/pluggy.egg-info/PKG-INFO 2017-09-06 15:53:21.000000000 +0200 +++ new/pluggy-0.6.0/pluggy.egg-info/PKG-INFO 2017-11-24 17:32:29.000000000 +0100 @@ -1,11 +1,12 @@ -Metadata-Version: 1.1 +Metadata-Version: 1.2 Name: pluggy -Version: 0.5.2 +Version: 0.6.0 Summary: plugin and hook calling mechanisms for python Home-page: https://github.com/pytest-dev/pluggy Author: Holger Krekel Author-email: holger@merlinux.eu License: MIT license +Description-Content-Type: UNKNOWN Description: pluggy - A minimalist production ready plugin system ==================================================== |pypi| |anaconda| |versions| |travis| |appveyor| @@ -103,10 +104,9 @@ Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluggy-0.5.2/setup.py new/pluggy-0.6.0/setup.py --- old/pluggy-0.5.2/setup.py 2017-08-29 02:26:09.000000000 +0200 +++ new/pluggy-0.6.0/setup.py 2017-11-24 14:37:36.000000000 +0100 @@ -14,7 +14,7 @@ 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy'] + [ ('Programming Language :: Python :: %s' % x) for x in - '2 2.6 2.7 3 3.3 3.4 3.5 3.6'.split()] + '2 2.7 3 3.4 3.5 3.6'.split()] with open('README.rst') as fd: long_description = fd.read() @@ -41,6 +41,7 @@ author='Holger Krekel', author_email='holger@merlinux.eu', url='https://github.com/pytest-dev/pluggy', + python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', classifiers=classifiers, packages=['pluggy'], ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluggy-0.5.2/testing/benchmark.py new/pluggy-0.6.0/testing/benchmark.py --- old/pluggy-0.5.2/testing/benchmark.py 2017-08-29 16:00:38.000000000 +0200 +++ new/pluggy-0.6.0/testing/benchmark.py 2017-11-16 04:57:28.000000000 +0100 @@ -2,7 +2,7 @@ Benchmarking and performance tests. """ import pytest -from pluggy import (_MultiCall, _LegacyMultiCall, HookImpl, HookspecMarker, +from pluggy import (_multicall, _legacymulticall, HookImpl, HookspecMarker, HookimplMarker) hookspec = HookspecMarker("example") @@ -28,7 +28,7 @@ @pytest.fixture( - params=[0, 1, 10, 100], + params=[10, 100], ids="hooks={}".format, ) def hooks(request): @@ -36,7 +36,7 @@ @pytest.fixture( - params=[0, 1, 10, 100], + params=[10, 100], ids="wrappers={}".format, ) def wrappers(request): @@ -44,7 +44,7 @@ @pytest.fixture( - params=[_MultiCall, _LegacyMultiCall], + params=[_multicall, _legacymulticall], ids=lambda item: item.__name__ ) def callertype(request): @@ -52,7 +52,7 @@ def inner_exec(methods, callertype): - return MC(methods, {'arg1': 1, 'arg2': 2, 'arg3': 3}, callertype).execute() + return MC(methods, {'arg1': 1, 'arg2': 2, 'arg3': 3}, callertype) def test_hook_and_wrappers_speed(benchmark, hooks, wrappers, callertype): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluggy-0.5.2/testing/test_details.py new/pluggy-0.6.0/testing/test_details.py --- old/pluggy-0.5.2/testing/test_details.py 2017-07-07 19:00:55.000000000 +0200 +++ new/pluggy-0.6.0/testing/test_details.py 2017-11-13 22:29:29.000000000 +0100 @@ -1,6 +1,8 @@ import warnings -from pluggy import PluginManager, HookimplMarker, HookspecMarker +import pytest + +from pluggy import PluginManager, HookimplMarker, HookspecMarker, _Result hookspec = HookspecMarker("example") hookimpl = HookimplMarker("example") @@ -93,3 +95,9 @@ warning = warns[-1] assert issubclass(warning.category, Warning) assert "Argument(s) ('arg2',)" in str(warning.message) + + +def test_result_deprecated(): + r = _Result(10, None) + with pytest.deprecated_call(): + assert r.result == 10 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluggy-0.5.2/testing/test_hookrelay.py new/pluggy-0.6.0/testing/test_hookrelay.py --- old/pluggy-0.5.2/testing/test_hookrelay.py 2017-09-05 15:27:35.000000000 +0200 +++ new/pluggy-0.6.0/testing/test_hookrelay.py 2017-11-24 14:29:35.000000000 +0100 @@ -24,8 +24,8 @@ plugin = Plugin() pm.register(plugin) - l = hook.hello(arg=3) - assert l == [4] + out = hook.hello(arg=3) + assert out == [4] assert not hasattr(hook, 'world') pm.unregister(plugin) assert hook.hello(arg=3) == [] @@ -64,6 +64,44 @@ assert comprehensible in str(exc.value) +def test_call_order(pm): + class Api(object): + @hookspec + def hello(self, arg): + "api hook 1" + + pm.add_hookspecs(Api) + + class Plugin1(object): + @hookimpl + def hello(self, arg): + return 1 + + class Plugin2(object): + @hookimpl + def hello(self, arg): + return 2 + + class Plugin3(object): + @hookimpl + def hello(self, arg): + return 3 + + class Plugin4(object): + @hookimpl(hookwrapper=True) + def hello(self, arg): + assert arg == 0 + outcome = yield + assert outcome.get_result() == [3, 2, 1] + + pm.register(Plugin1()) + pm.register(Plugin2()) + pm.register(Plugin3()) + pm.register(Plugin4()) # hookwrapper should get same list result + res = pm.hook.hello(arg=0) + assert res == [3, 2, 1] + + def test_firstresult_definition(pm): class Api(object): @hookspec(firstresult=True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluggy-0.5.2/testing/test_method_ordering.py new/pluggy-0.6.0/testing/test_method_ordering.py --- old/pluggy-0.5.2/testing/test_method_ordering.py 2017-08-29 16:00:38.000000000 +0200 +++ new/pluggy-0.6.0/testing/test_method_ordering.py 2017-11-24 14:29:35.000000000 +0100 @@ -215,42 +215,42 @@ def test_add_tracefuncs(he_pm): - l = [] + out = [] class api1(object): @hookimpl def he_method1(self): - l.append("he_method1-api1") + out.append("he_method1-api1") class api2(object): @hookimpl def he_method1(self): - l.append("he_method1-api2") + out.append("he_method1-api2") he_pm.register(api1()) he_pm.register(api2()) def before(hook_name, hook_impls, kwargs): - l.append((hook_name, list(hook_impls), kwargs)) + out.append((hook_name, list(hook_impls), kwargs)) def after(outcome, hook_name, hook_impls, kwargs): - l.append((outcome, hook_name, list(hook_impls), kwargs)) + out.append((outcome, hook_name, list(hook_impls), kwargs)) undo = he_pm.add_hookcall_monitoring(before, after) - he_pm.hook.he_method1() - assert len(l) == 4 - assert l[0][0] == "he_method1" - assert len(l[0][1]) == 2 - assert isinstance(l[0][2], dict) - assert l[1] == "he_method1-api2" - assert l[2] == "he_method1-api1" - assert len(l[3]) == 4 - assert l[3][1] == l[0][0] + he_pm.hook.he_method1(arg=1) + assert len(out) == 4 + assert out[0][0] == "he_method1" + assert len(out[0][1]) == 2 + assert isinstance(out[0][2], dict) + assert out[1] == "he_method1-api2" + assert out[2] == "he_method1-api1" + assert len(out[3]) == 4 + assert out[3][1] == out[0][0] undo() - he_pm.hook.he_method1() - assert len(l) == 4 + 2 + he_pm.hook.he_method1(arg=1) + assert len(out) == 4 + 2 def test_hook_tracing(he_pm): @@ -268,18 +268,18 @@ raise ValueError() he_pm.register(api1()) - l = [] - he_pm.trace.root.setwriter(l.append) + out = [] + he_pm.trace.root.setwriter(out.append) undo = he_pm.enable_tracing() try: indent = he_pm.trace.root.indent he_pm.hook.he_method1(arg=1) assert indent == he_pm.trace.root.indent - assert len(l) == 2 - assert 'he_method1' in l[0] - assert 'finish' in l[1] + assert len(out) == 2 + assert 'he_method1' in out[0] + assert 'finish' in out[1] - l[:] = [] + out[:] = [] he_pm.register(api2()) with pytest.raises(ValueError): @@ -290,15 +290,17 @@ undo() -def test_prefix_hookimpl(): +@pytest.mark.parametrize('include_hookspec', [True, False]) +def test_prefix_hookimpl(include_hookspec): pm = PluginManager(hookspec.project_name, "hello_") - class HookSpec(object): - @hookspec - def hello_myhook(self, arg1): - """ add to arg1 """ + if include_hookspec: + class HookSpec(object): + @hookspec + def hello_myhook(self, arg1): + """ add to arg1 """ - pm.add_hookspecs(HookSpec) + pm.add_hookspecs(HookSpec) class Plugin(object): def hello_myhook(self, arg1): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluggy-0.5.2/testing/test_multicall.py new/pluggy-0.6.0/testing/test_multicall.py --- old/pluggy-0.5.2/testing/test_multicall.py 2017-08-29 16:00:38.000000000 +0200 +++ new/pluggy-0.6.0/testing/test_multicall.py 2017-11-24 14:29:35.000000000 +0100 @@ -1,6 +1,7 @@ import pytest -from pluggy import _MultiCall, HookImpl, HookCallError, _LegacyMultiCall +from pluggy import _multicall, _legacymulticall, HookImpl, HookCallError +from pluggy.callers import _LegacyMultiCall from pluggy import HookspecMarker, HookimplMarker @@ -9,23 +10,23 @@ def test_uses_copy_of_methods(): - l = [lambda: 42] - mc = _MultiCall(l, {}) + out = [lambda: 42] + mc = _LegacyMultiCall(out, {}) repr(mc) - l[:] = [] + out[:] = [] res = mc.execute() return res == 42 def MC(methods, kwargs, firstresult=False): - caller = _MultiCall + caller = _multicall hookfuncs = [] for method in methods: f = HookImpl(None, "<temp>", method, method.example_impl) hookfuncs.append(f) if '__multicall__' in f.argnames: - caller = _LegacyMultiCall - return caller(hookfuncs, kwargs, {"firstresult": firstresult}) + caller = _legacymulticall + return caller(hookfuncs, kwargs, firstresult=firstresult) def test_call_passing(): @@ -45,9 +46,7 @@ p1 = P1() p2 = P2() - multicall = MC([p1.m, p2.m], {"x": 23}) - assert "23" in repr(multicall) - reslist = multicall.execute() + reslist = MC([p1.m, p2.m], {"x": 23}) assert len(reslist) == 2 # ensure reversed order assert reslist == [23, 17] @@ -63,19 +62,15 @@ def f(self, x, y): return x + y - multicall = MC([f, A().f], dict(x=23, y=24)) - assert "'x': 23" in repr(multicall) - assert "'y': 24" in repr(multicall) - reslist = multicall.execute() + reslist = MC([f, A().f], dict(x=23, y=24)) assert reslist == [24 + 23, 24] - assert "2 results" in repr(multicall) def test_keyword_args_with_defaultargs(): @hookimpl def f(x, z=1): return x + z - reslist = MC([f], dict(x=23, y=24)).execute() + reslist = MC([f], dict(x=23, y=24)) assert reslist == [24] @@ -83,8 +78,8 @@ @hookimpl def f(x): return x - multicall = MC([f], {}) - pytest.raises(HookCallError, multicall.execute) + with pytest.raises(HookCallError): + MC([f], {}) def test_call_subexecute(): @@ -97,8 +92,7 @@ def n(): return 1 - call = MC([n, m], {}, firstresult=True) - res = call.execute() + res = MC([n, m], {}, firstresult=True) assert res == 2 @@ -111,53 +105,53 @@ def m2(): return None - res = MC([m1, m2], {}, {"firstresult": True}).execute() + res = MC([m1, m2], {}, firstresult=True) assert res == 1 - res = MC([m1, m2], {}, {}).execute() + res = MC([m1, m2], {}, {}) assert res == [1] def test_hookwrapper(): - l = [] + out = [] @hookimpl(hookwrapper=True) def m1(): - l.append("m1 init") + out.append("m1 init") yield None - l.append("m1 finish") + out.append("m1 finish") @hookimpl def m2(): - l.append("m2") + out.append("m2") return 2 - res = MC([m2, m1], {}).execute() + res = MC([m2, m1], {}) assert res == [2] - assert l == ["m1 init", "m2", "m1 finish"] - l[:] = [] - res = MC([m2, m1], {}, {"firstresult": True}).execute() + assert out == ["m1 init", "m2", "m1 finish"] + out[:] = [] + res = MC([m2, m1], {}, firstresult=True) assert res == 2 - assert l == ["m1 init", "m2", "m1 finish"] + assert out == ["m1 init", "m2", "m1 finish"] def test_hookwrapper_order(): - l = [] + out = [] @hookimpl(hookwrapper=True) def m1(): - l.append("m1 init") + out.append("m1 init") yield 1 - l.append("m1 finish") + out.append("m1 finish") @hookimpl(hookwrapper=True) def m2(): - l.append("m2 init") + out.append("m2 init") yield 2 - l.append("m2 finish") + out.append("m2 finish") - res = MC([m2, m1], {}).execute() + res = MC([m2, m1], {}) assert res == [] - assert l == ["m1 init", "m2 init", "m2 finish", "m1 finish"] + assert out == ["m1 init", "m2 init", "m2 finish", "m1 finish"] def test_hookwrapper_not_yield(): @@ -165,9 +159,8 @@ def m1(): pass - mc = MC([m1], {}) with pytest.raises(TypeError): - mc.execute() + MC([m1], {}) def test_hookwrapper_too_many_yield(): @@ -176,27 +169,26 @@ yield 1 yield 2 - mc = MC([m1], {}) with pytest.raises(RuntimeError) as ex: - mc.execute() + MC([m1], {}) assert "m1" in str(ex.value) assert (__file__ + ':') in str(ex.value) @pytest.mark.parametrize("exc", [ValueError, SystemExit]) def test_hookwrapper_exception(exc): - l = [] + out = [] @hookimpl(hookwrapper=True) def m1(): - l.append("m1 init") + out.append("m1 init") yield None - l.append("m1 finish") + out.append("m1 finish") @hookimpl def m2(): raise exc with pytest.raises(exc): - MC([m2, m1], {}).execute() - assert l == ["m1 init", "m1 finish"] + MC([m2, m1], {}) + assert out == ["m1 init", "m1 finish"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluggy-0.5.2/testing/test_pluginmanager.py new/pluggy-0.6.0/testing/test_pluginmanager.py --- old/pluggy-0.5.2/testing/test_pluginmanager.py 2017-09-05 15:27:35.000000000 +0200 +++ new/pluggy-0.6.0/testing/test_pluginmanager.py 2017-11-24 14:33:01.000000000 +0100 @@ -1,4 +1,5 @@ import pytest +import types from pluggy import (PluginValidationError, HookCallError, HookimplMarker, HookspecMarker) @@ -25,16 +26,16 @@ assert pm.is_registered(a1) pm.register(a2, "hello") assert pm.is_registered(a2) - l = pm.get_plugins() - assert a1 in l - assert a2 in l + out = pm.get_plugins() + assert a1 in out + assert a2 in out assert pm.get_plugin('hello') == a2 assert pm.unregister(a1) == a1 assert not pm.is_registered(a1) - l = pm.list_name_plugin() - assert len(l) == 1 - assert l == [("hello", a2)] + out = pm.list_name_plugin() + assert len(out) == 1 + assert out == [("hello", a2)] def test_has_plugin(pm): @@ -162,25 +163,25 @@ pm.add_hookspecs(Hooks) pm.hook.he_method1.call_historic(kwargs=dict(arg=1)) - l = [] + out = [] class Plugin(object): @hookimpl def he_method1(self, arg): - l.append(arg) + out.append(arg) pm.register(Plugin()) - assert l == [1] + assert out == [1] class Plugin2(object): @hookimpl def he_method1(self, arg): - l.append(arg * 10) + out.append(arg * 10) pm.register(Plugin2()) - assert l == [1, 10] + assert out == [1, 10] pm.hook.he_method1.call_historic(kwargs=dict(arg=12)) - assert l == [1, 10, 120, 12] + assert out == [1, 10, 120, 12] def test_with_result_memorized(pm): @@ -191,8 +192,8 @@ pm.add_hookspecs(Hooks) he_method1 = pm.hook.he_method1 - he_method1.call_historic(lambda res: l.append(res), dict(arg=1)) - l = [] + he_method1.call_historic(lambda res: out.append(res), dict(arg=1)) + out = [] class Plugin(object): @hookimpl @@ -200,7 +201,7 @@ return arg * 10 pm.register(Plugin()) - assert l == [10] + assert out == [10] def test_with_callbacks_immediately_executed(pm): @@ -225,15 +226,15 @@ def he_method1(self, arg): return arg * 30 - l = [] + out = [] pm.register(Plugin1()) pm.register(Plugin2()) he_method1 = pm.hook.he_method1 - he_method1.call_historic(lambda res: l.append(res), dict(arg=1)) - assert l == [20, 10] + he_method1.call_historic(lambda res: out.append(res), dict(arg=1)) + assert out == [20, 10] pm.register(Plugin3()) - assert l == [20, 10, 30] + assert out == [20, 10, 30] def test_register_historic_incompat_hookwrapper(pm): @@ -244,12 +245,12 @@ pm.add_hookspecs(Hooks) - l = [] + out = [] class Plugin(object): @hookimpl(hookwrapper=True) def he_method1(self, arg): - l.append(arg) + out.append(arg) with pytest.raises(PluginValidationError): pm.register(Plugin()) @@ -266,8 +267,8 @@ def he_method1(arg): return arg * 10 - l = pm.hook.he_method1.call_extra([he_method1], dict(arg=1)) - assert l == [10] + out = pm.hook.he_method1.call_extra([he_method1], dict(arg=1)) + assert out == [10] def test_call_with_too_few_args(pm): @@ -284,7 +285,8 @@ 0 / 0 pm.register(Plugin1()) with pytest.raises(HookCallError): - pm.hook.he_method1() + with pytest.warns(UserWarning): + pm.hook.he_method1() def test_subset_hook_caller(pm): @@ -295,17 +297,17 @@ pm.add_hookspecs(Hooks) - l = [] + out = [] class Plugin1(object): @hookimpl def he_method1(self, arg): - l.append(arg) + out.append(arg) class Plugin2(object): @hookimpl def he_method1(self, arg): - l.append(arg * 10) + out.append(arg * 10) class PluginNo(object): pass @@ -315,26 +317,26 @@ pm.register(plugin2) pm.register(plugin3) pm.hook.he_method1(arg=1) - assert l == [10, 1] - l[:] = [] + assert out == [10, 1] + out[:] = [] hc = pm.subset_hook_caller("he_method1", [plugin1]) hc(arg=2) - assert l == [20] - l[:] = [] + assert out == [20] + out[:] = [] hc = pm.subset_hook_caller("he_method1", [plugin2]) hc(arg=2) - assert l == [2] - l[:] = [] + assert out == [2] + out[:] = [] pm.unregister(plugin1) hc(arg=2) - assert l == [] - l[:] = [] + assert out == [] + out[:] = [] pm.hook.he_method1(arg=1) - assert l == [10] + assert out == [10] def test_multicall_deprecated(pm): @@ -349,3 +351,24 @@ def test_add_hookspecs_nohooks(pm): with pytest.raises(ValueError): pm.add_hookspecs(10) + + +def test_reject_prefixed_module(pm): + """Verify that a module type attribute that contains the project + prefix in its name (in this case `'example_*'` isn't collected + when registering a module which imports it. + """ + pm._implprefix = 'example' + conftest = types.ModuleType("conftest") + src = (""" +def example_hook(): + pass +""") + exec(src, conftest.__dict__) + conftest.example_blah = types.ModuleType("example_blah") + name = pm.register(conftest) + assert name == 'conftest' + assert getattr(pm.hook, 'example_blah', None) is None + assert getattr(pm.hook, 'example_hook', None) # conftest.example_hook should be collected + assert pm.parse_hookimpl_opts(conftest, 'example_blah') is None + assert pm.parse_hookimpl_opts(conftest, 'example_hook') == {} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluggy-0.5.2/testing/test_tracer.py new/pluggy-0.6.0/testing/test_tracer.py --- old/pluggy-0.5.2/testing/test_tracer.py 2016-11-18 16:53:05.000000000 +0100 +++ new/pluggy-0.6.0/testing/test_tracer.py 2017-11-24 14:29:35.000000000 +0100 @@ -6,21 +6,21 @@ rootlogger = _TagTracer() log = rootlogger.get("pytest") log("hello") - l = [] - rootlogger.setwriter(l.append) + out = [] + rootlogger.setwriter(out.append) log("world") - assert len(l) == 1 - assert l[0] == "world [pytest]\n" + assert len(out) == 1 + assert out[0] == "world [pytest]\n" sublog = log.get("collection") sublog("hello") - assert l[1] == "hello [pytest:collection]\n" + assert out[1] == "hello [pytest:collection]\n" def test_indent(): rootlogger = _TagTracer() log = rootlogger.get("1") - l = [] - log.root.setwriter(lambda arg: l.append(arg)) + out = [] + log.root.setwriter(lambda arg: out.append(arg)) log("hello") log.root.indent += 1 log("line1") @@ -32,8 +32,8 @@ log("line5") log.root.indent -= 1 log("last") - assert len(l) == 7 - names = [x[:x.rfind(' [')] for x in l] + assert len(out) == 7 + names = [x[:x.rfind(' [')] for x in out] assert names == [ 'hello', ' line1', ' line2', ' line3', ' line4', ' line5', 'last'] @@ -57,12 +57,12 @@ log = rootlogger.get("1") log2 = log.get("2") assert log2.tags == tuple("12") - l = [] - rootlogger.setprocessor(tuple("12"), lambda *args: l.append(args)) + out = [] + rootlogger.setprocessor(tuple("12"), lambda *args: out.append(args)) log("not seen") log2("seen") - assert len(l) == 1 - tags, args = l[0] + assert len(out) == 1 + tags, args = out[0] assert "1" in tags assert "2" in tags assert args == ("seen",) @@ -77,13 +77,13 @@ rootlogger = _TagTracer() log = rootlogger.get("1") log2 = log.get("2") - l = [] - log2.setmyprocessor(lambda *args: l.append(args)) + out = [] + log2.setmyprocessor(lambda *args: out.append(args)) log("not seen") - assert not l + assert not out log2(42) - assert len(l) == 1 - tags, args = l[0] + assert len(out) == 1 + tags, args = out[0] assert "1" in tags assert "2" in tags assert args == (42,) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluggy-0.5.2/tox.ini new/pluggy-0.6.0/tox.ini --- old/pluggy-0.5.2/tox.ini 2017-07-20 04:54:24.000000000 +0200 +++ new/pluggy-0.6.0/tox.ini 2017-11-24 14:37:36.000000000 +0100 @@ -1,12 +1,14 @@ [tox] -envlist=check,py{26,27,34,35,36,py}-pytest{28,29,30} +envlist=check,docs,py{27,34,35,36,py}-pytestrelease,py{27,36}-pytest{master,features} [testenv] commands=py.test {posargs:testing/} +setenv= + _PYTEST_SETUP_SKIP_PLUGGY_DEP=1 deps= - pytest28: pytest~=2.8.0 - pytest29: pytest~=2.9.0 - pytest30: pytest~=3.0.0 + pytestrelease: pytest + pytestmaster: git+https://github.com/pytest-dev/pytest.git@master + pytestfeatures: git+https://github.com/pytest-dev/pytest.git@features [testenv:benchmark] commands=py.test {posargs:testing/benchmark.py} @@ -35,6 +37,8 @@ #--pyargs --doctest-modules --ignore=.tox addopts=-rxsX norecursedirs=.tox ja .hg .env* +filterwarnings = + error [flake8] max-line-length=99