Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialCode and Theory Dev Team
Courses Plus Student 47,334 PointsRaise ValueError makes another error message fail
Please see my code below. The error occurs when it asks how many tickets you'd like, you input a string, and it fails to coerce it to an int.
This is occurring because I passed the ValueError as err, but then it also passes an ugly error when you input a string and the program tries to coerce it into an int. Craig does not address this in the video. I originally used an if statement within the "else" of the "try except else" but wanted to try to imitate Craig's code. What would be a practical solution to fix Craig's code?
Thanks.
TICKET_PRICE = 10
tickets_remaining = 100
while tickets_remaining > 0:
print("{} tickets remain!".format(tickets_remaining))
name = input("Hello, what is your name? ")
print("Hi {}! There are {} tickets remaining!".format(name,tickets_remaining))
tickets_wanted = input("How many tickets would you like, {}? ".format(name))
try:
tickets_wanted = int(tickets_wanted)
#Raise a value error if request exceeds ticket count
if tickets_wanted > tickets_remaining:
raise ValueError("There are only {} tickets remaining!".format(tickets_remaining))
except ValueError as err:
print("Oh no something went wrong pls halp. {} Please try again.".format(err))
else:
total_cost = tickets_wanted * TICKET_PRICE
print("That will be ${}, {}.".format(total_cost,name))
confirm_yes = input("Are you sure you want to proceed? (yes/no) ")
confirm_yes = confirm_yes.lower()
if confirm_yes == "yes":
tickets_remaining -= tickets_wanted #what if tickets_wanted > tickets_remaining?
print("SOLD!!!")
else:
print("WOOPS!!!")
print("Tickets are now sold out!".format(name))
Code and Theory Dev Team
Courses Plus Student 47,334 PointsHi Renato, yes that is what I meant. Craig called it that in the video. Sorry for the confusion.
So it is passing the ACTUAL error message into err and displaying that, too. It works as intended when you ask for more tickets than are remaining.
Austin Loos
7,046 PointsRan into this same problem as well, but I found a solution that works, although it might not be the cleanest. So all we're doing here is essentially bringing the error to the users attention by calling a ValueError, but the thing is, we can really raise any error we want, like say a NameError, it doesn't always have to be a ValueError. We get that ugly error message because we're formatting err and passing whatever it stores onto the user, which works great for stopping overticketing errors, but its kinda lousy for the original value error we encountered because of what it passes back to the user. But if you create another exception, like the one below, you can get both messages to show cleanly.
try:
num_tickets = input("How many tickets would you like {}? ".format(name))
num_tickets = int(num_tickets)
if num_tickets > tickets_remaining:
raise NameError("There are only {} tickets remaining.".format(tickets_remaining))
except NameError as err:
print("Oh no, we ran into an issue! {} Please try again.".format(err))
except ValueError:
print("Oh no, we ran into an issue! Please try again.")
else:
print("Your total is ${}, {}!".format(total_cost(num_tickets, TICKET_PRICE), name))
confirm_purchase()
tickets_remaining -= num_tickets
2 Answers
Eric M
11,546 PointsHi Code & Theory Team, Hi Austin,
It's not a great idea to use NameError
for this as NameError is for when a program calls to a reference (or handle, or name) that is not defined.
If you need to pass a different message just include it in the error, if you don't want another message from the same error type to display you have two options.
The simple and not very good option is to add some conditional logic:
ERROR_MSG_START = "Oh no, we ran into an issue!"
ERROR_MSG_END = "Please try again."
try:
num_tickets = input("How many tickets would you like {}? ".format(name))
num_tickets = int(num_tickets)
if num_tickets > tickets_remaining:
raise ValueError(f"There are only {tickets_remaining} tickets remaining.")
except ValueError as err:
if "tickets remaining" in err:
print(f"{ERROR_MSG_START} {err} {ERROR_MSG_END}")
elif "invalid literal" in err:
print(f"{ERROR_MSG_START} You must enter an integer {ERROR_MSG_END}")
else:
print(f"{ERROR_MSG_START} {ERROR_MSG_END}")
else:
print(f"Your total is ${total_cost(num_tickets, TICKET_PRICE)}, {name}!")
confirm_purchase()
tickets_remaining -= num_tickets
The best way is to create a custom exception type:
class OutOfTicketsError(Exception):
pass
try:
num_tickets = input("How many tickets would you like {}? ".format(name))
num_tickets = int(num_tickets)
if num_tickets > tickets_remaining:
raise OutOfTicketsError(f"There are only {tickets_remaining} tickets remaining.")
except ValueError:
print(f"{ERROR_MSG_START} {ERROR_MSG_END}")
except OutOfTicketsError as err:
print(f"{ERROR_MSG_START} {err} {ERROR_MSG_END}")
else:
print(f"Your total is ${total_cost(num_tickets, TICKET_PRICE)}, {name}!")
confirm_purchase()
tickets_remaining -= num_tickets
Though I would still want to give the user more information on requiring an integer for the value error in the second example.
Cheers,
Eric
Austin Loos
7,046 PointsThanks Eric, that cleared things up. The first example may not be as clean as the second, but it's more in line with what we've learned so far, so it may be easier for other students to pick up on. Just a heads up though, you're going to get a TypeError if you try to iterate through err without coercing it to a string first. This works though.
if "tickets remaining" in str(err):
print(f"{ERROR_MSG_START} {err} {ERROR_MSG_END}")
I like your custom exception solution much better, but we haven't covered classes yet, so it may be confusing to some who are learning python as their first language. Either way, thanks for the input; much better than my NameError bandaid.
Eric M
11,546 PointsCheers Austin,
I agree about the Custom Exception maybe being too much for an absolute beginner, the branching is absolutely okay for getting a programming running while learning, it's still good to know that there are better solutions available when you're ready for them.
Thanks for catching my TypeError :)
Let's keep it DRY and use one type cast instead of three (two of ours and the one print()
does for us).
except ValueError as err:
error_string = str(err)
if "tickets remaining" in error_string:
print(f"{ERROR_MSG_START} {error_string} {ERROR_MSG_END}")
elif "invalid literal" in error_string:
print(f"{ERROR_MSG_START} You must enter an integer {ERROR_MSG_END}")
else:
print(f"{ERROR_MSG_START} {ERROR_MSG_END}")
Happy Coding!
Brendan Lindsay
3,408 PointsIn case this helps, I was able to handle this in a different way. I kept the ValueError except, but added an "if/else statement" with "continues" to handle the other two input issues.
TICKET_PRICE = 10
tickets_remaining = 100
def calculate_price(num_of_tickets):
return num_of_tickets * TICKET_PRICE
while tickets_remaining > 0:
print("There are {} tickets remaining.".format(tickets_remaining))
name = input("What is your name? ")
requested_tickets = input("How many tickets would you like, {}? ".format(name))
try:
requested_tickets = int(requested_tickets)
except ValueError as err:
print("Please enter a whole number (Ex: 4)")
else:
if requested_tickets > tickets_remaining:
print("Sorry, we do not that many tickets left.")
continue
elif requested_tickets < 0:
print("Sorry, please enter a positive value.")
continue
else:
order_price = calculate_price(requested_tickets)
order_status = input("Alright {}, that will be ${}. Do you want to continue? Y/N ".format(name,order_price))
if order_status.upper() == 'Y':
print("Great! Order confirmed.")
tickets_remaining -= requested_tickets
else:
print("Your order has been cancelled.")
print("There are no more tickets remaining")
Renato Guzman
51,437 PointsRenato Guzman
51,437 PointsIf you put a string. You get an error similar to:
Oh no something went wrong pls halp. invalid literal for int() with base 10: 'Seven' Please try again.
. Is theinvalid literal for int() with base 10: 'Seven'
the ugly error?