Skip to content

Commit

Permalink
Remove spec_opts from muli-callers
Browse files Browse the repository at this point in the history
Multi-call loop(s) should not care about spec opts - only whether
or not the first result should be returned.
Fix issue where a collected but unmarked hook not having
`_HookCaller.spec_opts` defined results in an attr error.

Resolves pytest-dev#99
  • Loading branch information
Tyler Goodlet committed Nov 18, 2017
1 parent f335bb5 commit 550f4b2
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 14 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

0 comments on commit 550f4b2

Please sign in to comment.