Исключение подобрано за пределами его функции - PullRequest
0 голосов
/ 21 января 2020

У меня есть текстовая программа, которая использует меню и подменю в стиле «while True:» l oop. Вы попадаете в подменю через верхнее меню - ИЗМЕНЕНО, чтобы включить код.

Когда я делаю выбор меню

def main():   
    import win32com.client, os, datetime, time, sys

    outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")

    try: #THIS IS NOT THE TRY/EXCEPT BLOCK CAUSING ISSUES
        itinbox = outlook.Folders("IT Department").Folders('Inbox')#Look at inbox of IT Dept inbox
        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
        #total number of emails in the inbox
        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.")

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

    #Get todays date based on system clock
    todayDate = datetime.date.today()

    senderDict = {email address : name} #redacted

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


    def topMenu():
        topMenuItems = ['Collect Attachments', 'View Senders', 'Edit Senders', 'Quit']

        while 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:
                    mainChoice0()
                    #break

                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")

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


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


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


    def mainChoice0(): #Collect Attachments
        check = 0 #Keep count of checked messages
        while True:
            try:
                ####Determine search range by date
                startDate = input("Enter a date dd-mm-yyyy: ")
                while startDate == "":
                    startDate = input("Enter a date dd-mm-yyyy: ")

                #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)
                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 option from listSender
                for msg in reversed(itcontents): #reversed() will go from most recent to oldest email based on date
                    if msg.Class == 43: #only search mail items (class 43)
                        #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.")

                        #Choose sender, reference index to name.
                        senderNum = int(input("Choose a sender (blank to exit): "))
                        senderChoice = listSender[senderNum]

                        #Search all
                        if senderNum == 0:
                            print("Searching for any sender")
                            #####Code to check emails runs after choosing a sender
                            #msg refers to a mail item object

                            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())

                                #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
                            else: print("There were", check, "messages.")
                                #break

                        elif senderNum <= len(listSender) and senderNum > 0:
                            print("you chose", senderChoice)
                            ##################### Search for a specific sender
                            ##################### Need to match chosen sender to dictionary so as to only save pdfs from that sender
                            #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
                            else: print("There were", check, "messages from", senderChoice)


                        elif ( senderNum != 0 
                        and 
                        ( 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()))
                                #break
                                #Stop searching inbox earlier than searchDate
                                if msg.SentOn.date() < searchDate: 
                                    break

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

            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 from", msg.SentOn.date())
                continue

    topMenu()
main()

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

1 Collect Attachments
2 View Senders
3 Edit Senders
4 Quit

Choose an option: 1
Chose Collect Attachments

Enter a date dd-mm-yyyy: 21-01-2020
Enter how many days previous to search through: 7
Your search starts from 2020-01-21 00:00:00 and ends on 2020-01-14

0 Search Any
1 Hazel Blue
2 Duo Security
3 Esker Australia Pty Ltd
4 iiNet Billing Team
5 TeamViewer Sales
6 ple.com.au Gnangara Warehouse Team
7 info@thereceptionist.com.au
8 Amazon Web Services
There are 9 options.

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

Проблема в том, что ValueError не должен появляться в подменю. Это все самоучка, поэтому я полагаю, что не понимаю, как происходит обработка исключений.

Ответы [ 2 ]

1 голос
/ 21 января 2020

Вот проблема:

>>> int("")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: ''

Поэтому, когда вы говорите «пусто для выхода» в своем подменю, вы должны либо:

  1. проверить пустую строку перед тем, как для преобразования в число
  2. используются только строки

Кстати, изучение пакета logging и использование logging.exception при подавлении исключений обычно полезно.

Кроме того, большие try предложения, которые вы используете, которые охватывают десятки строк кода, обычно не одобряются, так как легко отлавливать непреднамеренные исключения, а затем, как вы заметили, трудно отладить их. Как правило, вы должны максимально ограничить свои пункты try, хотя, конечно, ваш пробег может отличаться.

1 голос
/ 21 января 2020

вы можете попробовать это, если какое-либо исключение генерируется в topMenu, тогда оно не будет go подменю, иначе оно перейдет в подменю и выполнит действие.

def main():
     def topMenu():
            while True:
                try:
                    # code if generate exception
                    subMenu()

                # you can fetch specific exception or general
                except Exception as e:
                    print(e)


        def subMenu():
            print("in submenu")
            # code here...  
        topMenu()
 main()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...