From 707226298a445016b72bb7bf749a5e4aee36c8e5 Mon Sep 17 00:00:00 2001 From: TomV Date: Wed, 7 Oct 2015 09:23:46 +0100 Subject: [PATCH 1/2] issue1035 add test for classes setting __getattr__ --- testing/python/collect.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/testing/python/collect.py b/testing/python/collect.py index f660a8ab1..228d58364 100644 --- a/testing/python/collect.py +++ b/testing/python/collect.py @@ -95,6 +95,16 @@ class TestClass: "*1 passed*", ]) + def test_issue1035_obj_has_getattr(self, testdir): + modcol = testdir.getmodulecol(""" + class Chameleon(object): + def __getattr__(self, name): + return True + chameleon = Chameleon() + """) + colitems = modcol.collect() + assert len(colitems) == 0 + class TestGenerator: def test_generative_functions(self, testdir): From 88c8dd96f93e1097eeb19156ee0f0084d334688c Mon Sep 17 00:00:00 2001 From: TomV Date: Wed, 7 Oct 2015 09:25:12 +0100 Subject: [PATCH 2/2] issue1035 Override inspect.isclass for python 2.6 --- CHANGELOG | 2 ++ _pytest/python.py | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 91b7f9972..0d326ef48 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,8 @@ 2.8.3.dev --------- +- fix #1035: collecting tests if test module level obj has __getattr__(). + Thanks Suor for the report and Bruno Oliveira / Tom Viner for the PR. 2.8.2 ----- diff --git a/_pytest/python.py b/_pytest/python.py index 32cf82668..b194031c7 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -4,6 +4,7 @@ import fnmatch import functools import py import inspect +import types import sys import pytest from _pytest.mark import MarkDecorator, MarkerError @@ -43,6 +44,14 @@ else: def _format_args(func): return inspect.formatargspec(*inspect.getargspec(func)) +if sys.version_info[:2] == (2, 6): + def isclass(object): + """ Return true if the object is a class. Overrides inspect.isclass for + python 2.6 because it will return True for objects which always return + something on __getattr__ calls (see #1035). + Backport of https://hg.python.org/cpython/rev/35bf8f7a8edc + """ + return isinstance(object, (type, types.ClassType)) def _has_positional_arg(func): return func.__code__.co_argcount @@ -2137,7 +2146,7 @@ def num_mock_patch_args(function): def getfuncargnames(function, startindex=None): # XXX merge with main.py's varnames - #assert not inspect.isclass(function) + #assert not isclass(function) realfunction = function while hasattr(realfunction, "__wrapped__"): realfunction = realfunction.__wrapped__