Add helpful error message when dealing with old-style classes

--HG--
extra : rebase_source : f94bedeb736bf453bf8d1a38fa50f9bfd47cd249
This commit is contained in:
David Wolever
2014-01-02 18:48:53 -05:00
parent 1ddcdbdfed
commit 5b03c2431d
4 changed files with 46 additions and 3 deletions

View File

@@ -1,3 +1,6 @@
0.3.2 (2014-01-02)
* Add helpful error message when used with old-style classes.
0.3.1 (2013-08-01)
* Fix bug: `nose_parameterized.param` wasn't being imported.

View File

@@ -11,9 +11,14 @@ from . import six
if six.PY3:
def new_instancemethod(f, *args):
return f
# Python 3 doesn't have an InstanceType, so just use a dummy type.
class InstanceType():
pass
else:
import new
new_instancemethod = new.instancemethod
from types import InstanceType
_param = namedtuple("param", "args kwargs")
@@ -140,6 +145,14 @@ class parameterized(object):
def make_bound_method(self, instance, func):
cls = type(instance)
if issubclass(cls, InstanceType):
raise TypeError((
"@parameterized can't be used with old-style classes, but "
"%r has an old-style class. Consider using a new-style "
"class, or '@parameterized.expand' "
"(see http://stackoverflow.com/q/54867/71522 for more "
"information on old-style classes)."
) %(instance, ))
im_f = new_instancemethod(func, None, cls)
setattr(cls, func.__name__, im_f)
return getattr(instance, func.__name__)
@@ -164,8 +177,8 @@ class parameterized(object):
code_context = frame[4] and frame[4][0].strip()
if not (code_context and code_context.startswith("class ")):
return []
_, parents = code_context.split("(", 1)
parents, _ = parents.rsplit(")", 1)
_, _, parents = code_context.partition("(")
parents, _, _ = parents.partition(")")
return eval("[" + parents + "]", frame[0].f_globals, frame[0].f_locals)
@classmethod

View File

@@ -1,6 +1,8 @@
from unittest import TestCase
from nose.tools import assert_equal
from nose.plugins.skip import SkipTest
from . import six
from .parameterized import parameterized, param
def assert_contains(haystack, needle):
@@ -20,6 +22,8 @@ missing_tests = set([
"test_on_TestCase('foo0', bar=None)",
"test_on_TestCase('foo1', bar=None)",
"test_on_TestCase('foo2', bar=42)",
"test_on_old_style_class('foo')",
"test_on_old_style_class('bar')",
])
test_params = [
@@ -75,3 +79,26 @@ def test_helpful_error_on_non_iterable_input():
def teardown_module():
missing = sorted(list(missing_tests))
assert_equal(missing, [])
def test_old_style_classes():
if six.PY3:
raise SkipTest("Py3 doesn't have old-style classes")
class OldStyleClass:
@parameterized(["foo"])
def parameterized_method(self, param):
pass
try:
list(OldStyleClass().parameterized_method())
except TypeError as e:
assert_contains(str(e), "new-style")
assert_contains(str(e), "parameterized.expand")
assert_contains(str(e), "OldStyleClass")
else:
raise AssertionError("expected TypeError not raised by old-style class")
class TestOldStyleClass:
@parameterized.expand(["foo", "bar"])
def test_old_style_classes(self, param):
missing_tests.remove("test_on_old_style_class(%r)" %(param, ))

View File

@@ -9,7 +9,7 @@ os.chdir(os.path.dirname(sys.argv[0]) or ".")
setup(
name="nose-parameterized",
version="0.3.1",
version="0.3.2",
url="https://github.com/wolever/nose-parameterized",
author="David Wolever",
author_email="david@wolever.net",