Skip to content

Commit

Permalink
Merge pull request #102 from tgoodlet/expose_spec_opts_regresion
Browse files Browse the repository at this point in the history
Self contained call loops
  • Loading branch information
goodboy authored Nov 19, 2017
2 parents 607862c + 19055e5 commit 0fbcb25
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 23 deletions.
13 changes: 8 additions & 5 deletions pluggy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,8 @@ def __init__(self, project_name, implprefix=None):
self._implprefix = implprefix
self._inner_hookexec = lambda hook, methods, kwargs: \
hook.multicall(
methods, kwargs, specopts=hook.spec_opts, hook=hook
methods, kwargs,
firstresult=hook.spec_opts.get('firstresult'),
)

def _hookexec(self, hook, methods, kwargs):
Expand Down Expand Up @@ -528,20 +529,22 @@ def __init__(self, trace):


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.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()
Expand All @@ -550,7 +553,7 @@ def set_specification(self, specmodule_or_class, spec_opts):
# 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 = []

Expand Down
15 changes: 6 additions & 9 deletions pluggy/callers.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,17 +105,16 @@ class _LegacyMultiCall(object):
# 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
def __init__(self, hook_impls, kwargs, firstresult=False):
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
self.firstresult = firstresult

def execute(self):
caller_kwargs = self.caller_kwargs
self.results = results = []
firstresult = self.specopts.get("firstresult")
firstresult = self.firstresult

while self.hook_impls:
hook_impl = self.hook_impls.pop()
Expand Down Expand Up @@ -144,21 +143,19 @@ def __repr__(self):
return "<_MultiCall %s, kwargs=%r>" % (status, self.caller_kwargs)


def _legacymulticall(hook_impls, caller_kwargs, specopts={}, hook=None):
def _legacymulticall(hook_impls, caller_kwargs, firstresult=False):
return _LegacyMultiCall(
hook_impls, caller_kwargs, specopts=specopts, hook=hook).execute()
hook_impls, caller_kwargs, firstresult=firstresult).execute()


def _multicall(hook_impls, caller_kwargs, specopts={}, hook=None):
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
specopts = hook.spec_opts if hook else specopts
results = []
firstresult = specopts.get("firstresult")
excinfo = None
try: # run impl and wrapper setup functions in a loop
teardowns = []
Expand Down
14 changes: 8 additions & 6 deletions testing/test_method_ordering.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,15 +290,17 @@ def he_method1(self):
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):
Expand Down
6 changes: 3 additions & 3 deletions testing/test_multicall.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def MC(methods, kwargs, firstresult=False):
hookfuncs.append(f)
if '__multicall__' in f.argnames:
caller = _legacymulticall
return caller(hookfuncs, kwargs, specopts={"firstresult": firstresult})
return caller(hookfuncs, kwargs, firstresult=firstresult)


def test_call_passing():
Expand Down Expand Up @@ -105,7 +105,7 @@ def m1():
def m2():
return None

res = MC([m1, m2], {}, {"firstresult": True})
res = MC([m1, m2], {}, firstresult=True)
assert res == 1
res = MC([m1, m2], {}, {})
assert res == [1]
Expand All @@ -129,7 +129,7 @@ def m2():
assert res == [2]
assert out == ["m1 init", "m2", "m1 finish"]
out[:] = []
res = MC([m2, m1], {}, {"firstresult": True})
res = MC([m2, m1], {}, firstresult=True)
assert res == 2
assert out == ["m1 init", "m2", "m1 finish"]

Expand Down

0 comments on commit 0fbcb25

Please sign in to comment.