diff --git a/attr/_make.py b/attr/_make.py index 7f6de470..dc72f0d6 100644 --- a/attr/_make.py +++ b/attr/_make.py @@ -160,6 +160,8 @@ def attributes(maybe_cl=None, these=None, :type no_init: bool """ def wrap(cl): + if getattr(cl, "__class__", None) is None: + raise TypeError("attrs only works with new-style classes.") _transform_attrs(cl, these) if not no_repr: cl = _add_repr(cl) @@ -172,12 +174,11 @@ def attributes(maybe_cl=None, these=None, return cl # attrs_or class type depends on the usage of the decorator. It's a class - # if it's used as `@attributes` but ``None`` (or a value passed) if used - # as `@attributes()`. - if isinstance(maybe_cl, type): - return wrap(maybe_cl) - else: + # if it's used as `@attributes` but ``None`` if used # as `@attributes()`. + if maybe_cl is None: return wrap + else: + return wrap(maybe_cl) def _attrs_to_tuple(obj, attrs): diff --git a/tests/test_make.py b/tests/test_make.py index 98a60a91..e0ee82a8 100644 --- a/tests/test_make.py +++ b/tests/test_make.py @@ -9,6 +9,7 @@ from __future__ import absolute_import, division, print_function import pytest from . import simple_attr +from attr._compat import PY3 from attr._make import ( Attribute, NOTHING, @@ -117,6 +118,17 @@ class TestAttributes(object): """ Tests for the `attributes` class decorator. """ + @pytest.mark.skipif(PY3, reason="No old-style classes in Py3") + def test_catches_old_style(self): + """ + Raises TypeError on old-style classes. + """ + with pytest.raises(TypeError) as e: + @attributes + class C: + pass + assert ("attrs only works with new-style classes.",) == e.value.args + def test_sets_attrs(self): """ Sets the `__attrs_attrs__` class attribute with a list of `Attribute`s.