1

I've been trying to write a small application that will help me manage specific outlook emails. I can currently access individual directories based on their name by recursively searching for them. However, I hit a small bump that I can't seem to get over.

import win32com.client

o = win32com.client.gencache.EnsureDispatch("Outlook.Application").GetNamespace("MAPI")

def dfr(folders, indent, tardir):
    try:
        for i in range(1, folders.Count+1):
            run = True
            folder = folders[i]
            dfr(folder.Folders, indent+1, tardir)
            try:
                if folder.Name == tardir:
                    if folder.Name == None:
                        print(folder.Name)
                        raise StopIteration
                    print(folder.Name)
                    return dfr(folders[i], indent, tardir)
            except StopIteration:
                break

    except UnboundLocalError:
        pass



tf = dfr(o.Folders, 0, "Journal")

print(tf)

What is expected is that, the function will recursively search the outlook until it finds the specified directory in the function call, in this example "Journal". The function finds it, and stops there. Because the function does print(folder) I know it stops at journal. However, when I try to return folder, it does not return the properly value and equates to None.

I don't need to return the other three variables from this function as they are only used for navigation..

Any suggestions?

EDIT: Response to below comment

Printout when recursively searching through the folders.

import win32com.client

o = win32com.client.gencache.EnsureDispatch("Outlook.Application").GetNamespace("MAPI")

def dfr(folders, indent, tardir):
    for i in range(1, folders.Count+1):
        run = True
        folder = folders[i]
        print('%sFolder %d: "%s"' %('\t'*indent,i,folder.Name))
        dfr(folder.Folders, indent+1, tardir)
        if folder.Name == tardir:
            if folder.Name == None:
                print(folder.Name)
                break
            print(folder.Name)
            return folder

tf = dfr(o.Folders, 0, "Journal")

print(tf)
Justin
  • 125
  • 1
  • 2
  • 12
  • 1
    `dfr(folder.Folders, indent+1, tardir)` => `return dfr(folder.Folders, indent+1, tardir)` – Jean-François Fabre Mar 16 '18 at 15:01
  • I only want to return folder. I specifically want to exclude the other two variables as they are only for navigation. EDIT: This change still only returns None. – Justin Mar 16 '18 at 15:08
  • 1
    you have exception handling branches that don't return anything. You have to return something there, or make so that exceptions don't happen – Jean-François Fabre Mar 16 '18 at 15:11
  • 1
    this is sloppy in a lot of ways. Your `for` loop should be `for f in folders:` and your nested try block doesn't serve any purpose. Consider a full rewrite – sadmicrowave Mar 16 '18 at 15:13
  • Forgive me, I'm a relative beginner in Python. I thought that the exception handling statements I had were valid. Could you elaborate on what's wrong with them please? – Justin Mar 16 '18 at 15:14
  • Can you paste a screenshot of your folders in outlook? Also, paste what the current output is, if any of the folders are printing at all. – sadmicrowave Mar 16 '18 at 15:20
  • I would think the first place to address your issue is on the `return` line. You are not returning the `folder` but instead you are calling the function again and expecting that to give you an output. If you are looking for the folder object of `Journal` it should just be `return folder[i]` – sadmicrowave Mar 16 '18 at 15:25
  • I've tried that too, and I get a TypeError specifying that MAPIObject doesn't support indexing. I would've thought because in each iteration I'm assigning folders[I] to folder I would be able to return the object of folder by using return folder. – Justin Mar 16 '18 at 15:30
  • 1
    Can you correct your indentation? There's no indented block after `def` so this is not valid python syntax. The second to last line also has an indentation level that doesn't match anything else. – Håken Lid Mar 16 '18 at 15:32
  • @sadmicrowave if I'm printing out the name of each object in the function, they print out perfectly. It's just returning the object that I'm running into issues with. – Justin Mar 16 '18 at 15:37
  • 1
    Can you post a complete example? We don't know what `o.Folders` is, and where you got it from. – Håken Lid Mar 16 '18 at 15:39
  • 1
    @HåkenLid updated. – Justin Mar 16 '18 at 15:42
  • 1
    Why are you explicitly raising a `StopIteration` exception instead of just using `break` directly? – chepner Mar 16 '18 at 15:44
  • @chepner I did that initially, but it wasn't making any difference. I was researching alternatives. – Justin Mar 16 '18 at 15:46
  • 1
    Never catch `UnboundLocalError`. Never handle, all the more, silence any exceptions unless you actually address the problem that they signal of. Your error is the result of this stupid decision. – ivan_pozdeev Mar 16 '18 at 15:54
  • @ivan_pozdeev You are correct, I had it there to troubleshoot something yesterday and forgot it there. I removed it now, yet I still am not returning the value properly. – Justin Mar 16 '18 at 15:57

1 Answers1

3

I don't know the win32com api, but if you want to do a depth first search, you can try something like this.

def dfr(folders, tardir):

    for folder in folders:  # if `folder` follows python convention, it should be iterable.
        if folder.Name == tardir: # is it the correct folder?
            return folder 
        match = dfr(folder.Folders, tardir)  # recurse into child folders
        if match: 
            # return result from recursive call of dfr() if successful
            # This was missing in your code, which is why it returns None
            return match 

tf = dfr(o.Folders, "Journal")
print(tf)

The reason why your function returns None, is that you only return if the folder name matches. But since that might happen several levels deep in the recursion, you also have to propagate the result up the stack to the initial caller. If you don't do that, python functions return None by default.

Håken Lid
  • 22,318
  • 9
  • 52
  • 67
  • The answer provided appears to have error type RecursionErrors. I believe this is because within each folder there are Items, which in this case they are the emails. `RecursionError: maximum recursion depth exceeded` – Justin Mar 16 '18 at 16:17
  • I made a typo resulting in an infinite recursion. Try the corrected code. – Håken Lid Mar 16 '18 at 16:36
  • Thank you!! I appreciate the notes, they helped me understand what I was doing incorrectly, on a fundamental level. – Justin Mar 16 '18 at 16:53