Each attrs-decorated class has a __attrs_attrs__ class attribute. It is a tuple of attr.Attribute carrying meta-data about each attribute.

So it is fairly simple to build your own decorators on top of attrs:

>>> import attr
>>> def print_attrs(cl):
...     print cl.__attrs_attrs__
>>> @print_attrs
... @attr.s
... class C(object):
...     a = attr.ib()
(Attribute(name='a', default=NOTHING, validator=None, repr=True, cmp=True, hash=True, init=True),)


The attr.s() decorator must be applied first because it puts __attrs_attrs__ in place! That means that is has to come after your decorator because:

def f():

is just syntactic sugar for:

def original_f():

f = a(b(original_f))