11

I am new to python and I am about to make this new program that will ask you for your birthday. I've made some try/except clauses to avoid people entering info in strings or to high numbers. I would like my program to find out if the info entered equals a date in the end. If it does I would like to have it printed and if not I would like it to find out what part of the user input was wrong. I have therefore made some if clauses in the last except clause with the idea that the errors would equal a message.

I would like to know if it is possible to make the program match the messages with the error to find out the specific error and figure out what part of the input was wrong.

My code looks like this:

try: 
    print(datetime.date(int(birthYear), int(birthMonth), int(birthDay)))
except TypeError:
    if ValueError == "ValueError: month must be in 1..12": 
        print("Month " + str(birthMonth) + " is out of range. The month must be a number in 1...12")
    if ValueError == "ValueError: year " + str(birthYear) + " is out of range": 
        print("Year " + str(birthMonth) + " is out of range. The year must be a number in " + str(datetime.MINYEAR) + "..." + str(datetime.MAXYEAR))
    if ValueError == "ValueError: day is out of range for month": 
        print("Day " + str(birthDay) + " is out of range. The day must be a number in 1..." + str(calendar.monthrange(birthYear, birthMonth)))
Georgy
  • 12,464
  • 7
  • 65
  • 73
SnitchingAuggie
  • 494
  • 3
  • 14
  • Does this answer your question? [Python: Catching specific exception](https://stackoverflow.com/questions/13531247/python-catching-specific-exception) – Georgy Mar 08 '21 at 10:01

2 Answers2

10

You were close. The trick is to use ValueError as e and compare your strings against str(e). It's also good practice to use if / elif rather than repeated if statements.

Here's a working example:

import calendar, datetime

try: 
    print(datetime.date(int(birthYear), int(birthMonth), int(birthDay)))
except ValueError as e:
    if str(e) == 'month must be in 1..12': 
        print('Month ' + str(birthMonth) + ' is out of range. The month must be a number in 1...12')
    elif str(e) == 'year {0} is out of range'.format(birthYear): 
        print('Year ' + str(birthMonth) + ' is out of range. The year must be a number in ' + str(datetime.MINYEAR) + '...' + str(datetime.MAXYEAR))
    elif str(e) == 'day is out of range for month': 
        print('Day ' + str(birthDay) + ' is out of range. The day must be a number in 1...' + str(calendar.monthrange(birthYear, birthMonth)))
jpp
  • 159,742
  • 34
  • 281
  • 339
  • 1
    Is comparing against the message strings an accepted practice? Are they well-defined? The documentation for `datetime.date` only says that a `ValueError` is raised. – Arndt Jonasson Apr 27 '18 at 22:48
  • Good question. Whether or not it's "accepted" is opinion. As far as I'm aware, it's the *only* way. In terms of "well-defined" `datetime` is part of the standard library. When you change Python versions you may see different error messages, and they may change in the future. If this is important, then a trivial workaround is to raise Exceptions yourself based on the same criteria (easy for this particular question). – jpp Apr 27 '18 at 22:51
  • Damn I didn't know I was that close to the answer. Tried to put e in before but not stringed. Thank you so much for the tip it really helped me out. I was about to try and find something about tracebacks and make them equal to but I couldn't figure it out. Thx a lot mate. I actually used the if statements because I was wondering if the program could find multiple numbers out of range or if it would just stop when the first was found – SnitchingAuggie Apr 27 '18 at 22:54
  • @SnitchingAuggie, When you catch an error you won't be able to catch a subsequent error with the same code. If this helped, feel free to accept (green tick on left). – jpp Apr 27 '18 at 22:58
  • @jpp The if statements couldn't run all together. the code stop at the first true statement. i was wondering if I could use a for loop like: for e: if str(e) == "month ..... – SnitchingAuggie Apr 27 '18 at 23:28
  • 1
    I don't think that's the issue. When an exception occurs, only one exception feeds downstream to `e`. You have to fix that problem (e.g. move year out of range to inside range) and run the code again to see if there are more errors. – jpp Apr 27 '18 at 23:29
  • @ArndtJonasson. different context but i've had good results testing generic SQLAlchemy exceptions for str content that indicates a table is missing, a specific type of error that can be expected in my app. I then reraise that as a custom TableMissingException. Puts the onus on you to know your domain, but it works just fine. – JL Peyret Apr 28 '18 at 18:54
0

Using dict so that you can add more easily

import calendar, datetime

birthYear= int(input('Birth year:'))
birthMonth= int(input('Birth month:'))
birthDay= int(input('Birth day:'))

error_dict = {
    'month must be in 1..12' : f'Month {birthMonth} is out of range. The month must be a number in 1...12',
     'year {0} is out of range':f'Year {birthMonth} is out of range. The year must be a number in  {datetime.MINYEAR} ...{datetime.MAXYEAR}',
    'day is out of range for month' : f'Day  {birthDay} is out of range. The day must be a number in 1... 12'
}
    
try: 
    print(datetime.date((birthYear), (birthMonth), (birthDay)))    
    
except ValueError as e:
    print(error_dict[str(e)])

Outputs

Birth year:32
Birth month:32
Birth day:32
Month 32 is out of range. The month must be a number in 1...12

[Program finished]
Subham
  • 397
  • 1
  • 6
  • 14