3
\$\begingroup\$

I am creating a server with Flask and it has quite a few routes. Most routes require a specific state, such as "logged in" or "process started". All of my functions and methods in packages will throw certain type of exceptions when the specific state is not matched. At the end my code ends up like this:

@app.route("/sayHello")
def sayHello():
    try:
        name = get_session_data("user", "name")

        # Some other stuff that throw meaningful exceptions

        return someTemplate

    except NotLoggedIn:
        return flask.redirect(flask.url_for("login"))

    except UserNotReadyToSayHello:
        return "You are not ready to say hello!", status.HTTP_400_BAD_REQUEST

    except UserHelloMessageNotDefined:
        return "You did not set up a greeting message!", status.HTTP_400_BAD_REQUEST

    except ConnectionToDatabaseFailed:
        return "Cannot access database", status.HTTP_500_INTERNAL_SERVER_ERROR

    except UnexpectedError:
        return "Something happened", status.HTTP_500_INTERNAL_SERVER_ERROR

Of course this is just an example I made up to demonstrate the problem, however it is more or less equivalent to the actual code.

This made programming the routes much easier than checking everything with if statements everywhere, however I ended up with a lot of except cases to the point where PyLint is telling me

Too many return statements (9/6)

How should I handle this situation? A lot of routes actually share a very similar sets of except cases.

\$\endgroup\$
1
\$\begingroup\$

Handling "too many" return statements.

If your linter tells you, that you have too many return statements, this is a hint. A linter is supposed to support you in writing quality code. If however your code needs that specific exception handling this is what you need to implement and you can ignore the linter's hint.
I am not sure whether you can break down the code into several methods, each handling only a part of the possible exceptions, since you decided not to share this essential part of the code with us (# Some other stuff that throw meaningful exceptions).

Re-use of exception handlers

If you want to re-use the exception handlers, you can refactor them into the __exit__ method of an appropriate context manager. Then you can do something like:

@app.route("/sayHello")
def sayHello():
    with ErrorHandler as error_handler:
        name = get_session_data("user", "name")

        # Some other stuff that throw meaningful exceptions

        return someTemplate

    return error_handler.retval

And re-use the respective context manager ErrorHandler accordingly.

\$\endgroup\$
  • \$\begingroup\$ This seems like a good strategy, but I think it won't work when I need to handle one extra exception that is not handled in the error handler. \$\endgroup\$ – Derek 朕會功夫 Nov 24 '17 at 21:19
  • \$\begingroup\$ Then you can still try and except it. \$\endgroup\$ – Richard Neumann Nov 24 '17 at 21:44
  • \$\begingroup\$ I ended up creating a decorator to handle common exceptions, and the try..except block remains inside to catch specific exceptions. \$\endgroup\$ – Derek 朕會功夫 Nov 25 '17 at 1:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.