reno-
reno-

Reputation: 335

Wrap get and set attributes methods without editing original Class

I'm trying to make some action before or after a property is get or/and set. The tricky part of this piece of code is that I cannot modify the original class.

No problem for method of the class, it works as expected. But I cannot found a way to deal with properties. I have an Error :

TypeError: readonly attribute

If someone might help me to find the right direction…

This is the Class I cannot modify :

class Test(object):
    def __init__(self):
        super(Test, self).__init__()
        self._param = None
        self._controler = None
        self._message = None
    @property
    def param(self):
        return self._param
    @param.setter
    def param(self, param):
        self._param = param

    @property
    def controler(self):
        return self._controler

    def message(self):
        print('message')

This is the wrapper I wrote to make the job, this will be part of my module

def add_things_before_and_after(function_to_enhance):
    def new_wrapper(self):
        print("Before function execution") 
        function_to_enhance(self)
        print("After function execution")
    return new_wrapper

This is the code to write to use the wrapper and instanciate the class

# this one works as expected
Test.message = add_things_before_and_after(Test.message)
# these two lines does not work
Test.param.fget = add_things_before_and_after(Test.param.fget)
Test.controler.fget = add_things_before_and_after(Test.controler.fget)

test = Test()
test.message()
test.param = 1
print(test.param)
print(test.controler)

Upvotes: 0

Views: 66

Answers (1)

kofrasa
kofrasa

Reputation: 2140

This is possible to do by overriding the entire param property with a new one. However, your decorator function must be fixed to return the value of the wrapped function.

The functools.wraps is a good way to preserve the properties (name, doc etc.) of the wrapped function.

from functools import wraps

def add_things_before_and_after(function_to_enhance):
    @wraps(function_to_enhance)
    def new_wrapper(self):
        print("Before function execution")
        r = function_to_enhance(self)
        print("After function execution")
        return r
    return new_wrapper

# this one works as expected
Test.message = add_things_before_and_after(Test.message)

# these two lines should work
Test.param = property(add_things_before_and_after(Test.param.fget), Test.param.fset)
Test.controler = property(add_things_before_and_after(Test.controler.fget), Test.controler.fset)

test = Test()
test.message()
test.param = 1
print(test.param)
print(test.controler)

# ==Output==
#
# Before function execution
# message
# After function execution
# Before function execution
# After function execution
# 1
# Before function execution
# After function execution
# None

Upvotes: 2

Related Questions