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 trial

Python

How to add custom exception for non-integer input

Hi all,

I'm going through the "All Together Now: Handling Exceptions" videos on Python Basics. I was noticing that (for all of the detail spent on improving the end-user experience by providing good error descriptions), we exposed a gnarly exception when we introduced the "raise ValueError" / "as err" portion of the exception code.

Immediately preceding that we were dealing with the input when users were entering "blue" for the integer value which had a nice exception message. However, when we moved on to accounting for the user entering too many tickets, we made it so that the exception code will then display a "invalid literal for int() with base 10: 'blue'" message.

Is there a way that we can override or improve that additional ValueError(err) message? I've been searching Google and just can't seem to find the right keywords to land on a good way to handle it. Basically I was trying to come up with an if statement that says basically "if num_tickets != (an integer), print("({} is not a valid number!)".format(num_tickets))

Thanks!

Dan

1 Answer

Hi Daniel,

One way to approach this would be to create a Custom Exception. This could be as simple as:

class NumberTooLargeException(Exception):
    pass

Then replace this line from Craig's code:

    raise ValueError("There are only {} tickets remaining".format(tickets_remaining))

With:

    raise NumberToolargeException(num_tickets, tickets_remaining)

You can then treat the except ValueError clause as dealing only with values that can't be expressed as ints (e.g., 'blue') and rewrite the corresponding print statement accordingly; and add a new except NumberToolargeException as err clause to provide specific guidance for this error:

except NumberTooLargeException as err:
    requested, available = err.args
    print(f'You requested {requested} tickets but there are only {available} tickets remaining')

Since you mentioned overriding ValueError, this is possible (at least, subclassing ValueError is possible), but not recommended. It's dangerous to subclass any error that you are likely to check for, since the except clause for the parent class will also catch errors for the subclass. For example, suppose we created NumberTooLargeException but as a subclass of ValueError instead of Exception and our try/except structure looked like this:

...
try:
    num_tickets = int(num_tickets)
    if num_tickets > tickets_remaining:
        raise NumberTooLargeException(num_tickets, tickets_remaining)
    except ValueError:
        # only strings that can't be turned into ints should end up here
        print("That input was not a number")
    except NumberTooLargeException as err:
        # numbers that are too big should end up here
        requested, available = err.args
        print(f'You requested {requested} tickets but there are only {available} tickets remaining')
    else:
        ...

At a glance, the above code looks fine. But try asking for more tickets than there are available and, because NumberTooLargeExceptions are ValueErrors, you'll get an error message telling you that it wasn't a number.

Hope that was of some use to you.

Cheers

Alex