97

In setUp() method of unittest I've setup some self variables, which are later referenced in actual tests. I've also created a decorator to do some logging. Is there a way in which I can access those self variables from decorator?

For the sake of simplicity, I'm posting this code:

def decorator(func):
    def _decorator(*args, **kwargs):
        # access a from TestSample
        func(*args, **kwargs)
    return _decorator

class TestSample(unittest.TestCase):    
    def setUp(self):
        self.a = 10

    def tearDown(self):
        # tear down code

    @decorator
    def test_a(self):
        # testing code goes here

What would be the best way of accessing a (set in setUp()) from decorator?

kevin
  • 2,172
  • 3
  • 18
  • 19

2 Answers2

150

Since you're decorating a method, and self is a method argument, your decorator has access to self at runtime. Obviously not at parsetime, because there are no objects yet, just a class.

So you change your decorator to:

def decorator(func):
    def _decorator(self, *args, **kwargs):
        # access a from TestSample
        print 'self is %s' % self
        return func(self, *args, **kwargs)
    return _decorator
Dave
  • 11,499
  • 5
  • 34
  • 46
1

You could actually also use functools.wraps to save the help(obj.method) information. In addition to that, if the decorator is only used in the class, it could be included to the class body:

from functools import wraps


class MyClass:

    def decorator(func):
        @wraps(func)
        def _decorator(self, *args, **kwargs):
            print("In decorator. self: ", self)
            return func(self, *args, **kwargs)

        return _decorator

    @decorator
    def somemethod(self, a: int, b: int = 5):
        """This is somemethod.

        Parameters
        ----------
        a:
            This is a.
        b:
            The b is optional argument. (Default: 5)
        """
        print("in somemethod")

Which works like this

>>> obj = MyClass()
>>> obj.somemethod()
In decorator. self:  <__main__.MyClass object at 0x7f0378df6920>
in somemethod

and will print the original docstring when calling help():

>>> help(obj.somemethod)

Help on method somemethod in module __main__:

somemethod(a: int, b: int = 5) method of __main__.MyClass instance
    This is somemethod.
    
    Parameters
    ----------
    a:
        This is a.
    b:
        The b is optional argument. (Default: 5)
:

instead of this (when omitting @wraps(func)):

>>> help(obj.somemethod)

Help on method _decorator in module __main__:

_decorator(*args, **kwargs) method of __main__.MyClass instance
(END)
Niko Föhr
  • 28,336
  • 10
  • 93
  • 96