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 #59
  • Loading branch information
Tyler Goodlet authored and goodboy committed Jun 3, 2020
1 parent 30a2f7c commit b267687
Show file tree
Hide file tree
Showing 2 changed files with 3 additions and 85 deletions.
73 changes: 0 additions & 73 deletions src/pluggy/callers.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,79 +81,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 src/pluggy/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import inspect
import sys
import warnings
from .callers import _legacymulticall, _multicall
from .callers import _multicall


class HookspecMarker(object):
Expand Down Expand Up @@ -264,25 +264,16 @@ 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,)

def __call__(self, *args, **kwargs):
if args:
raise TypeError("hook calling supports only keyword arguments")
assert not self.is_historic()

if self.spec and self.spec.argnames:
notincall = (
set(self.spec.argnames) - set(["__multicall__"]) - set(kwargs.keys())
)
notincall = set(self.spec.argnames) - set(kwargs.keys())
if notincall:
warnings.warn(
"Argument(s) {} which are declared in the hookspec "
Expand Down

0 comments on commit b267687

Please sign in to comment.