Exceptions are the way to comfortably route and handle errors in non-trivial programs. But a clear concept is helpful to not make a random hack out of that when programs grow.
(E.g. catching builtin ValueError
far away or return
ing / continuing by chance would quickly become hairy.)
There is the main difference between errors caused
- by invalid / odd user input
- by bugs
- by dynamic system / environment limits.
A reasonable way of separating, routing and handling these errors is:
(A) Catch or compare for user input errors very early near the point of potential happening. React immediately for simple recoveries / repetitions. Otherwise (for breaking out) convert to an enriched exception which can be catched and distinguished further down or at the bottom of the call stack (or by the default handler sys.excepthook
)
(B) Let crash down bug exceptions to the bottom of the call stack - unhandled; or possibly initiate comfortable bug presentation and feedback action.
(C) For system environment errors choose an approach between (A) and (B) depending on how much context, detail & comfort info you want to be present at the current stage of development.
This way this could become a scalable pattern for user oriented error handling in your example:
# Shows scalable user oriented error handling
import sys, traceback
DEBUG = 0
class UserInputError(Exception):
pass
def excercise5():
print("Programming Excercise 5")
print("This program calculates the cost of an order.")
# NOTE: eval() and input() was dangerous
s = input("Enter the weight in pounds: ")
try:
pound = float(s)
except ValueError as ev:
raise UserInputError("Number required for weight, not %r" % s, ev)
if pound < 0:
raise UserInputError("Positive weight required, not %r" % pound)
shippingCost = (0.86 * pound) + 1.50
coffee = (10.50 * pound) + shippingCost
if pound == 1:
print(pound,"pound of coffee costs $", coffee)
else:
print(pound,"pounds of coffee costs $", coffee)
print()
if __name__ == '__main__':
try:
excercise5()
except UserInputError as ev:
print("User input error (please retry):")
print(" ", ev.args[0])
if DEBUG and len(ev.args) > 1:
print(" EXC:", ev.args[1], file=sys.stderr)
except (EnvironmentError, KeyboardInterrupt) as ev:
print("Execution error happend:")
print(" ", traceback.format_exception_only(ev.__class__, ev)[0])
except Exception:
print("Please report this bug:")
traceback.print_exc()