Исключение обрабатывается неправильной функцией? (Python 3.х) - PullRequest
0 голосов
/ 04 февраля 2020

Я создал программу для проверки электронных писем и получения вложений от указанных c отправителей в Outlook. Существует главное меню и подменю, два меню представляют собой уникальные функции, заключенные в отдельные блоки try-кроме, чтобы справиться с неверным вводом. Когда я намеренно ввожу неправильный ввод в подменю, он отображает исключение из главного меню. Это то, как должна работать обработка исключений, или есть способ решить эту проблему?

Я ПРЕДЫДУЩАЯ использовал два цикла стиля While True: для каждого меню. Я подумал, что это может означать, что верхнее меню l oop все еще работает после того, как я получил доступ к подменю, в результате чего оно использует обработку исключений из верхнего меню l oop со входом подменю. Я изменил его, чтобы при переходе в другие меню текущее меню l oop сменилось на False. К сожалению, в подменю все еще отображаются исключения из верхнего меню, в то время как в верхнем меню никогда не отображаются исключения из подменю (насколько я встречал).

import win32com.client, os, datetime, time, sys

def main():
   #Opens Microsoft Outlook as outlook
   outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")

   ######These variables are in a try except clause because itcontents will throw an error when
   ###### a sender uses something like emojis in their subject line.

   try:
       itinbox = outlook.Folders("IT Department").Folders('Inbox')#Look at inbox of IT Dept folder
       itcontents = itinbox.Items #messages in the inbox        
       newMail = itcontents.GetLast() #GetLast is the most RECENT email.
       nextMail = itcontents.GetPrevious() #The next most recent email after .GetLast()
       mailSubj = newMail.Subject #The subject header
       totalEmails = itcontents.Count
       #print("Most recent mail:", newMail) #subject header of most recent email
       #print("sent from:", newMail.Sender)

   except UnicodeEncodeError: #unsupported characters
       print("Most recent message had unsupported characters.")



   #Shows the 'class' value of the most recent inbox item.
   for msg_class in range(1):
       print("Message class value of most recent inbox item is:", itcontents.GetLast().Class)

   emailUser = os.getlogin()
   print("Current user is", emailUser)

   todayDate = datetime.date.today()

   #############
   #A dictionary of sender addresses and associated sender names
   #Some addresses are sent on behalf of/bounced from another address
   #Use str(msg.SentOnBehalfOfName) in this case because the bounce address will change

   senderDict = {"sender name" : "sender email"} #redacted details, there are about 10 unique emails

   listSender = list(senderDict.values())
   listSender.insert(0, "Search Any")


   ############Top level menu

   def topMenu():
       topMenuItems = ['Collect Attachments', 'View Senders', 'Edit Senders', 'Quit']
       topMenuDisplay = True
       while topMenuDisplay == True:
           try:
               for count, item in enumerate(topMenuItems,1):
                   print(count, item)
               mainChoice = int(input('\nChoose an option: ')) #subtract one to match enumerate to index
               mainChoice -= 1
               print("Chose", topMenuItems[mainChoice], "\n")

               ###Collect Attachments
               if mainChoice == 0:
                   topMenuDisplay = False #Intended to stop the topMenu loop
                   mainChoice0() #Go to sub menu

               elif mainChoice == 1:
                   print(senderDict, "\n")
                   input("Press any key")
                   continue

               elif mainChoice == 2:
                   print("coming soon\n")
                   continue

               elif mainChoice == 3:
                   input("Press any key to exit.")
                   sys.exit("Goodbye")

               #avoid negative number index access, still displays a menu choice but prints error
               elif mainChoice < 0: 
                   print("Your choice is not listed.")
                   continue

               #For any other input I haven't considered
               else:
                   print("Your choice is not listed.")
                   continue

           except ValueError: #Not int
               print("You did not enter a valid number at topMenu() (ValueError)")
               continue


           except AttributeError:
               print("You did not enter a valid number at topMenu() (AttributeError)")
               continue


           except IndexError: #outside range
               print("Selection was not in the list at topMenu() (IndexError)")
               continue


############# Sub menu to collect email attachments from sender dictionary

   def mainChoice0(): 
       check = 0 #Keep count of checked messages

       mainChoiceDisplay0 = True

       #Make a folder on user desktop if it doesn't exist
       if not os.path.exists("C:\\Users\\"+emailUser+"\\Desktop\\Invoices from Outlook\\"):
           os.makedirs("C:\\Users\\"+emailUser+"\\Desktop\\Invoices from Outlook\\")
           print("Created folder 'Invoices from Outlook' on user desktop.")


       while mainChoiceDisplay0 == True:
           try:
               ####Determine search range by date
               startDate = input("Enter a date dd-mm-yyyy (blank to exit): ")
               if startDate == "":
                   mainChoiceDisplay0 = False
                   topMenu()

               #strptime will convert startDate from a string to a usable date
               startDate = datetime.datetime.strptime(startDate, "%d-%m-%Y") #class and module are called datetime hence datetime.datetime.strptime
               searchRange = int(input("Enter how many days previous to search through: "))
               searchDate = startDate.date() - datetime.timedelta(days = searchRange)#Subtract number of days from user input date
               print("Your search starts from", startDate, "and ends on", searchDate, "\n")

               #display list of senders for mainChoice == 0
               for count, item in enumerate(listSender,0): 
                   print(count, item)
               print("There are", len(listSender), "options.\n")



               #Choose sender from menu
               senderNum = input("Choose a sender (blank to exit): ")
               if senderNum == "":
                   mainChoiceDisplay0 = False
                   topMenu()
               else:
                   senderNum = int(senderNum)

               senderChoice = listSender[senderNum]

               #Search all
               if senderNum == 0:
                   print("Searching for any sender")


                   for msg in reversed(itcontents): #reversed() will go from most recent to oldest email based on date
                       if msg.Class == 43:

                           if ( (str(msg.SenderEmailAddress) or str(msg.Subject) or str(msg.Sender) or str(msg.SentOnBehalfOfName)) in senderDict and (msg.SentOn.date() >= searchDate and msg.SentOn.date() <= startDate.date())):
                               check += 1

                               print(check, "messages from", msg.SenderEmailAddress, "on", msg.SentOn.date())
                                                       ###############################
                               #print("Looking at", msg, msg.SentOn.date()) #uncomment this to see details about every message

                               #Check attachment file format string, invoices are usually PDFs.
                               #x refers to the attachment. Not every message from a listed sender has an attachment, those messages still add to count check.
                               for x in msg.Attachments:
                                   if str(".pdf").casefold() in str(x): #casfold() checks possible upper or lower case combinations e.g PdF or pDf
                                       x.SaveAsFile("C:\\Users\\"+emailUser+"\\Desktop\\Invoices from Outlook\\" + str(msg.SentOn.date()) + str(msg.SenderEmailAddress) + x.FileName)
                                       print("Saved attachment", x, "from", str(msg.Sender()), "on", str(msg.SentOn.date()))
                                       #break
                                       #Stop searching inbox earlier than searchDate
                                       if msg.SentOn.date() < searchDate: 
                                           break


               elif senderNum <= len(listSender) and senderNum > 0:
                   print("you chose", senderChoice)

                   #msg refers to an inbox object, msg.Class == 43 is a mail item object
                   for msg in reversed(itcontents): #reversed() will go from most recent to oldest email based on date
                       if msg.Class == 43: #Don't call msg.Class as a function with (), just need integer value

                   #senderNum != 0 for all other valid options.
                   #https://www.programiz.com/python-programming/methods/built-in/any
                   #list comprehension [x for x in [items] if y in x] https://python-3-patterns-idioms-test.readthedocs.io/en/latest/Comprehensions.html
                           if ( (str(msg.SenderEmailAddress) or str(msg.Subject) or str(msg.Sender) or str(msg.SentOnBehalfOfName)) in senderDict
                           and
                           (msg.SentOn.date() >= searchDate and msg.SentOn.date() <= startDate.date())
                           and
                           any([field for field in [str(msg.SenderEmailAddress), str(msg.Subject), str(msg.Sender), str(msg.SentOnBehalfOfName)] if str(senderChoice) in field])
                           ):
                               check += 1
                               print(check, "messages from", msg.SenderEmailAddress, "on", msg.SentOn.date()) #keep count of checked messages

                               #Check attachment file format, invoices are usually PDFs
                               #x refers to the attachment. Not every message from a listed sender has an attachment, those messages still add to count check.
                               for x in msg.Attachments:
                                   if str(".pdf").casefold() in str(x): #casfold() cheks upper or lower case format
                                           x.SaveAsFile("C:\\Users\\"+emailUser+"\\Desktop\\Invoices from Outlook\\" + str(msg.SentOn.date()) + str(msg.SenderEmailAddress) + x.FileName)
                                           print("Saved attachment", x, "from", str(msg.Sender()), "on", str(msg.SentOn.date()))

                               #Stop searching inbox earlier than searchDate
                               if msg.SentOn.date() < searchDate: 
                                   break



           except UnicodeEncodeError: #unsupported characters
               print("Subject line could not be parsed.")
               #continue

           except OverflowError: #caused by invalid or very old date e.g 01-01-0000
               print("Date calculation caused an overflow error, possibly because you entered a very old date e.g 01-01-0000.")
               #break

           except AttributeError: #The email was the wrong class for the attribute msg.Sender or you tried to use an attribute that doesn't work for that method
               print("Attribute error (not class 43 mail) for item - ", msg, msg.SentOn.date())
               continue

   topMenu()
main() 

Вывод выглядит так:

Message class value of most recent inbox item is: 43
Current user is camerona
1 Collect Attachments
2 View Senders
3 Edit Senders
4 Quit

Choose an option: 1
Chose Collect Attachments

####Sub menu starts here

Enter a date dd-mm-yyyy (blank to exit): 04-02-2020
Enter how many days previous to search through: 1
Your search starts from 2020-02-04 00:00:00 and ends on 2020-02-03

0 Search Any
1 redacted1
2 redacted2
3 redacted3
4 redacted4
5 redacted5
6 redacted6
7 redacted7
8 redacted8
There are 9 options.

Choose a sender (blank to exit):
a
You did not enter a valid number at topMenu() (ValueError)

Итак, как вы можете видеть, когда я набираю 'a' в подменю, чтобы вызвать исключение, оно обрабатывается topMenu ().

1 Ответ

0 голосов
/ 04 февраля 2020

Во время корректного чтения моего вопроса я заметил, что у меня нет исключения для ValueError в подменю. После того, как я добавил except ValueError: в mainChoice0 (), подменю теперь использует это исключение, а не исключение из topMenu ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...