Search code examples
pythonoopjinja2cherrypy

How to derive class with decorated method?


I have several similar python cherrypy applications

application_one.py

import cherrypy

class Class(object):

    @cherrypy.tools.jinja(a='a', b='b')
    @cherrypy.expose
    def index(self):
        return {
            'c': 'c'
        }

application_two.py

import cherrypy

class Class(object):

    @cherrypy.tools.jinja(a='a2', b='b2')
    @cherrypy.expose
    def index(self):
        return {
            'c': 'c2'
        } 

....

application_n.py

import cherrypy

class Class(object):

    @cherrypy.tools.jinja(a='aN', b='bN')
    @cherrypy.expose
    def index(self):
        return {
            'c': 'cN'
        }

I want to make parent class and derive it in all applications. Something like this

parent.py

import cherrypy

class ParentClass(object):

    _a = None
    _b = None
    _c = None

    @cherrypy.tools.jinja(a=self._a, b=self._b)
    @cherrypy.expose
    def index(self):
        return {
            'c': self._c
        }

application_one.py

import parent

class Class(ParentClass):

    _a = 'a'
    _b = 'b'
    _c = 'c'

application_two.py

import parent

class Class(ParentClass):

    _a = 'a2'
    _b = 'b2'
    _c = 'c2'

How to send params for index method decorator from derived classes?

Now I get error

NameError: name 'self' is not defined


Solution

  • Decorators are applied when you define the class. When defining a class, you are not running a method and thus self is not defined. There is no instance for self to refer to.

    You'd have to use a metaclass instead, that adds the decorator when building the subclass, or you'd have to use a class decorator, that applies the right decorator after the class has been defined.

    The class decorator could be:

    def add_decorated_index(cls):
        @cherrypy.tools.jinja(a=cls._a, b=cls._b)
        @cherrypy.expose
        def index(self):
            return {
                'c': self._c
            }
    
        cls.index = index
        return cls
    

    then apply this to the subclasses:

    import parent
    
    @parent.add_decorated_index
    class Class(parent.ParentClass):
        _a = 'a'
        _b = 'b'
        _c = 'c'