nathancahill
nathancahill

Reputation: 10850

Subclass Python class with same decorators

I'm using Flask-Classy to write a Flask app using class based views.

My base class is called SlugView. It catches URLs like example.com/124/catchy-article-name:

class SlugView(FlaskView):
    @route('/<id>')
    @route('/<id>/<slug>')
    def get(self, id, slug=None)
        raise NotImplementedError

My second class is called ArticleView:

class ArticleView(SlugView):
    def get(self, id, slug=None):
        return render_template('article.html', article=get_article_by_id(id))

What decorator magic can I use to have the subclassed function inherit the same decorators as the parent class?

Upvotes: 0

Views: 319

Answers (1)

Sean Vieira
Sean Vieira

Reputation: 159895

Magic? Yes. Decorator magic? No. Do you object to metaclass magic?

class InheritableRoutesMeta(type):
    def __new__(cls, cls_name, bases, attributes):
        for name, value in attributes.items():
            if not callable(value):
                continue
            for base in bases:
                super_method = getattr(base, name)
                if super_method and hasattr(super_method, "_rule_cache"):
                   value._rule_cache = super_method._rule_cache
                   break

        return super(InheritableRoutesMeta, cls).__new__(cls, cls_name,
                                                         bases, attributes)

Then you should be able to do something like this:

class ArticleView(SlugView, metaclass=InheritableRoutesMeta):
    # Use the keyword argument metaclass for Python 3
    # For Python 2, remove the argument and uncomment the below
    # __metaclass__ = InheritableRoutesMeta

    def get(self, id, slug=None):
        return render_template('article.html', article=get_article_by_id(id))

Warning: This is based on an internal property. If Flask-Classy chooses to change how it stores these decorators the above code will break (assuming that it works in the first place). If you really need this, it is worth filing an issue with the creator(s) to either make this property part of the public API or to provide another way of doing what you are doing. They may choose not to do either, but at least then they are aware of the use case.

Upvotes: 1

Related Questions