From 9b21d3f206a7bca7e38d8a18e2537ef26cd2de34 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Tue, 19 Nov 2013 15:33:52 +0100 Subject: [PATCH] internally make varnames() deal with classes's __init__, although it's not needed by pytest itself atm. Also fix caching. Fixes issue376. --- CHANGELOG | 4 ++++ _pytest/core.py | 29 +++++++++++++++++++++++------ testing/test_core.py | 12 ++++++++++-- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f87174e31..d859cad21 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -48,6 +48,10 @@ Unreleased - xfail a test on pypy that checks wrong encoding/ascii (pypy does not error out). fixes issue385. +- internally make varnames() deal with classes's __init__, + although it's not needed by pytest itself atm. Also + fix caching. Fixes issue376. + Changes between 2.4.1 and 2.4.2 ----------------------------------- diff --git a/_pytest/core.py b/_pytest/core.py index f6edb3317..0f33f4bb8 100644 --- a/_pytest/core.py +++ b/_pytest/core.py @@ -304,19 +304,36 @@ class MultiCall: return kwargs def varnames(func): + """ return argument name tuple for a function, method, class or callable. + + In case of a class, its "__init__" method is considered. + For methods the "self" parameter is not included unless you are passing + an unbound method with Python3 (which has no supports for unbound methods) + """ + cache = getattr(func, "__dict__", {}) try: - return func._varnames - except AttributeError: + return cache["_varnames"] + except KeyError: pass - if not inspect.isfunction(func) and not inspect.ismethod(func): - func = getattr(func, '__call__', func) - ismethod = inspect.ismethod(func) + if inspect.isclass(func): + try: + func = func.__init__ + except AttributeError: + return () + ismethod = True + else: + if not inspect.isfunction(func) and not inspect.ismethod(func): + func = getattr(func, '__call__', func) + ismethod = inspect.ismethod(func) rawcode = py.code.getrawcode(func) try: x = rawcode.co_varnames[ismethod:rawcode.co_argcount] except AttributeError: x = () - py.builtin._getfuncdict(func)['_varnames'] = x + try: + cache["_varnames"] = x + except TypeError: + pass return x class HookRelay: diff --git a/testing/test_core.py b/testing/test_core.py index 4c102e21f..edc573107 100644 --- a/testing/test_core.py +++ b/testing/test_core.py @@ -438,6 +438,15 @@ def test_varnames(): assert varnames(A().f) == ('y',) assert varnames(B()) == ('z',) +def test_varnames_class(): + class C: + def __init__(self, x): + pass + class D: + pass + assert varnames(C) == ("x",) + assert varnames(D) == () + class TestMultiCall: def test_uses_copy_of_methods(self): l = [lambda: 42] @@ -654,8 +663,7 @@ def test_default_markers(testdir): def test_importplugin_issue375(testdir): testdir.makepyfile(qwe="import aaaa") - with pytest.raises(ImportError) as excinfo: - importplugin("qwe") + excinfo = pytest.raises(ImportError, lambda: importplugin("qwe")) assert "qwe" not in str(excinfo.value) assert "aaaa" in str(excinfo.value)