flask-classy
flask-classy copied to clipboard
Fix issue #22 (rule lookup does not count inheritance)
Fix issue https://github.com/apiguy/flask-classy/issues/22
The issue is with cache strictly bound to the class object. Rule lookup doesn't count inheritance correctly.
Then, if you have
class BaseView(FlaskView):
@route('/delete/<id>')
def delete(self, id=None):
pass
class PostsView(BaseView):
@route('test') # any route to provide new cache obj instance
def test(self): # and break behavior
pass
It generates
Map(...
<Rule '/posts/<id>' (OPTIONS, DELETE) ...>,
)
While it should generate
Map(...
<Rule '/delete/<id>' (HEAD, OPTIONS, GET) ...>
)
Diff looks a bit scary but basically i added just 3 lines to deal with inheritance. This fix passes all tests.
I fixed this fragment
if hasattr(cls, "_rule_cache") and name in cls._rule_cache:
for idx, cached_rule in enumerate(cls._rule_cache[name]):
...
elif name in special_methods:
...
by wrapping in .mro()
lookup loop:
for _cls in cls.mro()[:-1]: # -1 to skip `object` lookup
if hasattr(_cls, "_rule_cache") and name in _cls._rule_cache:
for idx, cached_rule in enumerate(_cls._rule_cache[name]):
...
break
else: # no break
if name in special_methods: # elif -> if
...
I'm not 100% sure about solution. Flask-Classy is kinda tricky ;) I'm sure even less about git though...
This is great. Let me play with it just a bit and add some tests specifically for it.
After the Python 3 changes (pretty substantial changes were needed) this will need to be modified. I think the general idea is still the right way to do it though. I'll spend some more time on this tomorrow and hopefully get it out.
Yep, thank you.