New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
register user errorhandler in the right order #1295
Conversation
error_builder.extend(registered_errors[0:i + 1]) | ||
found = i | ||
break | ||
if found == -1: |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
I honestly like this a lot more than #1291, although I am wondering if we could sort exception handlers similarly to routes: with a key function. |
error_builder.extend(tailed_errors[0:i]) | ||
error_builder.append((exception, f)) | ||
error_builder.extend(tailed_errors[i:]) | ||
self.registered_errors = error_builder |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This version seems to work as well:
|
good idea! you don’t adress the profoundly broken logic in this line though. and i think you both misunderstand the performance characteristics of my approach. the “heavy” feel mainly comes from the fact that my dict subclass tries to transparently alias error codes and default error classes. else it will likely be faster than this. why? because you here have one central error registry realized as list. mine is one registry per error code, in the form of a dict. this here works by traversing the whole registry for a blueprint until a matching error is found. also things like mine works by traversing the mro and looking for a match in a dict for each class in the mro: O(len(mro)-2), which is mostly less than 3 or so. also note that the code in |
Yeah, about that... I think it's at least a small step in the right direction if we just remove that if-statement. I played around with this locally, it's actually pretty hard to unify HTTP exceptions and errorcodes.
Maybe I should've clarified that I mostly like the idea of sorting a single list of handlers more than having a custom dict-like object. It's mostly easier to read (and audit) for me. |
doesn’t my PR completely and transparently address this issue? if not, why didn’t you tell me yet ;)
as said: it could also be a normal dict; the only difference is that valid HTTP error codes are converted to their canonical HTTPException subclass on item access. if you don’t like something about that part, again: why didn’t you simply state your concerns in my PR? what are those concerns? The real backing dict is just one attribute access away: i’m going out on a limb and say you didn’t try it. it’s actually very simple and as clear as it is ordered: error_handler_spec = {
blueprint1: { ... },
None: {
None: { # all exceptions not a subclass of HTTPException
NonHTTPException: some_handler_function,
...
},
403: { # all exceptions that are a subclass of Forbidden (403)
Forbidden: some_handler_function,
ForbiddenSubclass: some_handler_function,
},
...
}
} |
@flying-sheep Maybe I've sounded too decisive, I've never intended to say that a particular PR is going to be merged. |
@untitaker Thanks! Your version looks good to me.
|
you might notice that my PR instates this separation whereas yours (and the existing code, due to a bug) doesn’t. please read the discussion in #1281, where i discovered the way the currently active code is broken.
because things might be forbidden for different reasons and it might be useful to react differently? e.g. the example in #1281: app = Flask(__name__)
app.errorhandler(403)
def default_forbidden():
return 'You’re not allowed to do that', 403
@app.errorhandler(CheatException)
def cheat(e):
return '''
You thought you’d get through with faking your score
while it really is {e.real_score}
'''.format(e=e), CheatException.code
@app.route('/submit_score/<score>')
def submit_score(score):
if not internal_score == score:
raise CheatException(internal_score)
well, performance is a secondary concern. i only responded to @untitaker’s implication that your PR is in some way “lighter” than mine, which i disagree with. i also think that it’s clearer to group handlers by HTTP code than just stuffing them all into a huge list.
no, i don’t :D look at the code in my previous comment: it’s just a nested dict |
#1291 has been merged. |
solved the problem proposed by #1291 in a lighter way,
thus determining the
exception hierarchy
at app setup time instead of running time.