Skip to content

Commit c883d1f

Browse files
authored
Merge pull request #27 from tgoodlet/master
Modernize varnames function
2 parents 7dae24c + 4776698 commit c883d1f

File tree

2 files changed

+48
-30
lines changed

2 files changed

+48
-30
lines changed

pluggy.py

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -627,50 +627,51 @@ def __repr__(self):
627627
return "<_MultiCall %s, kwargs=%r>" % (status, self.kwargs)
628628

629629

630-
def varnames(func, startindex=None):
631-
""" return argument name tuple for a function, method, class or callable.
630+
def varnames(func):
631+
"""Return argument name tuple for a function, method, class or callable.
632632
633633
In case of a class, its "__init__" method is considered.
634634
For methods the "self" parameter is not included unless you are passing
635-
an unbound method with Python3 (which has no supports for unbound methods)
635+
an unbound method with Python3 (which has no support for unbound methods)
636636
"""
637637
cache = getattr(func, "__dict__", {})
638638
try:
639639
return cache["_varnames"]
640640
except KeyError:
641641
pass
642+
642643
if inspect.isclass(func):
643644
try:
644645
func = func.__init__
645646
except AttributeError:
646647
return ()
647-
startindex = 1
648-
else:
649-
if not inspect.isfunction(func) and not inspect.ismethod(func):
650-
try:
651-
func = getattr(func, '__call__', func)
652-
except Exception:
653-
return ()
654-
if startindex is None:
655-
startindex = int(inspect.ismethod(func))
648+
elif not inspect.isroutine(func): # callable object?
649+
try:
650+
func = getattr(func, '__call__', func)
651+
except Exception:
652+
return ()
656653

657-
try:
658-
rawcode = func.__code__
659-
except AttributeError:
654+
try: # func MUST be a function or method here or we won't parse any args
655+
spec = inspect.getargspec(func)
656+
except TypeError:
660657
return ()
658+
659+
args, defaults = spec.args, spec.defaults
660+
args = args[:-len(defaults)] if defaults else args
661+
662+
# strip any implicit instance arg
663+
if args:
664+
if inspect.ismethod(func) or (
665+
'.' in getattr(func, '__qualname__', ()) and args[0] == 'self'
666+
):
667+
args = args[1:]
668+
669+
assert "self" not in args # best naming practises check?
661670
try:
662-
x = rawcode.co_varnames[startindex:rawcode.co_argcount]
663-
except AttributeError:
664-
x = ()
665-
else:
666-
defaults = func.__defaults__
667-
if defaults:
668-
x = x[:-len(defaults)]
669-
try:
670-
cache["_varnames"] = x
671+
cache["_varnames"] = args
671672
except TypeError:
672673
pass
673-
return x
674+
return tuple(args)
674675

675676

676677
class _HookRelay:
@@ -700,8 +701,7 @@ def set_specification(self, specmodule_or_class, spec_opts):
700701
assert not self.has_spec()
701702
self._specmodule_or_class = specmodule_or_class
702703
specfunc = getattr(specmodule_or_class, self.name)
703-
argnames = varnames(specfunc, startindex=inspect.isclass(specmodule_or_class))
704-
assert "self" not in argnames # sanity check
704+
argnames = varnames(specfunc)
705705
self.argnames = ["__multicall__"] + list(argnames)
706706
self.spec_opts = spec_opts
707707
if spec_opts.get("historic"):

testing/test_pluggy.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,23 @@ def pm():
1717
return PluginManager("example")
1818

1919

20-
@pytest.fixture
21-
def he_pm(pm):
20+
@pytest.fixture(
21+
params=[
22+
lambda spec: spec,
23+
lambda spec: spec()
24+
],
25+
ids=[
26+
"don't instantiate",
27+
"instatiate"
28+
],
29+
)
30+
def he_pm(request, pm):
2231
class Hooks:
2332
@hookspec
2433
def he_method1(self, arg):
2534
return arg + 1
2635

27-
pm.add_hookspecs(Hooks)
36+
pm.add_hookspecs(request.param(Hooks))
2837
return pm
2938

3039

@@ -725,8 +734,17 @@ def __init__(self, x):
725734
class D:
726735
pass
727736

737+
class E(object):
738+
def __init__(self, x):
739+
pass
740+
741+
class F(object):
742+
pass
743+
728744
assert varnames(C) == ("x",)
729745
assert varnames(D) == ()
746+
assert varnames(E) == ("x",)
747+
assert varnames(F) == ()
730748

731749

732750
def test_formatdef():

0 commit comments

Comments
 (0)