Skip to content

Commit

Permalink
Drop __multicall__!
Browse files Browse the repository at this point in the history
Drop the `_LegacyMultiCall` type and it's recursion "fun".
We've got a faster and simpler function-loop approach now with
`pluggy.callers._multicall()` it's been doing great in production!

Resolves pytest-dev#59
  • Loading branch information
Tyler Goodlet committed May 22, 2018
1 parent cab120f commit e129923
Show file tree
Hide file tree
Showing 2 changed files with 3 additions and 83 deletions.
71 changes: 0 additions & 71 deletions pluggy/callers.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,77 +77,6 @@ def get_result(self):
_reraise(*ex) # noqa


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 _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.caller_kwargs["__multicall__"] = self
self.firstresult = firstresult

def execute(self):
caller_kwargs = self.caller_kwargs
self.results = results = []
firstresult = self.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 _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).
Expand Down
15 changes: 3 additions & 12 deletions pluggy/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
import inspect
import warnings
from .callers import _legacymulticall, _multicall
from .callers import _multicall


class HookspecMarker(object):
Expand Down Expand Up @@ -192,7 +192,7 @@ def set_specification(self, specmodule_or_class, spec_opts):
specfunc = getattr(specmodule_or_class, self.name)
# get spec arg signature
argnames, self.kwargnames = varnames(specfunc)
self.argnames = ["__multicall__"] + list(argnames)
self.argnames = list(argnames)
self.spec_opts.update(spec_opts)
if spec_opts.get("historic"):
self._call_history = []
Expand Down Expand Up @@ -230,14 +230,6 @@ def _add_hookimpl(self, hookimpl):
i -= 1
methods.insert(i + 1, hookimpl)

if '__multicall__' in hookimpl.argnames:
warnings.warn(
"Support for __multicall__ is now deprecated and will be"
"removed in an upcoming release.",
DeprecationWarning
)
self.multicall = _legacymulticall

def __repr__(self):
return "<_HookCaller %r>" % (self.name,)

Expand All @@ -246,8 +238,7 @@ def __call__(self, *args, **kwargs):
raise TypeError("hook calling supports only keyword arguments")
assert not self.is_historic()
if self.argnames:
notincall = set(self.argnames) - set(['__multicall__']) - set(
kwargs.keys())
notincall = set(self.argnames) - set(kwargs.keys())
if notincall:
warnings.warn(
"Argument(s) {} which are declared in the hookspec "
Expand Down

0 comments on commit e129923

Please sign in to comment.