Finds a file or subdirectory from the given
    path, defaulting to a breadth-first search.
    :param target:      str of file or subdirectory to be found
    :param from_path:   str of path from which to search (defaults to relative)
    :param direction:   str enum of up, down, both
    :param depth_first: bool of changes search to depth-first
    :return:            str of path to desired file or subdirectory

def find_path(target, from_path=None, direction='both', depth_first=False):
    """
    Finds a file or subdirectory from the given
    path, defaulting to a breadth-first search.
    :param target:      str of file or subdirectory to be found
    :param from_path:   str of path from which to search (defaults to relative)
    :param direction:   str enum of up, down, both
    :param depth_first: bool of changes search to depth-first
    :return:            str of path to desired file or subdirectory
    """
    from_path = from_path if from_path else relative_path('', 2)

    if direction == 'up' or direction == 'both':
        path = from_path
        for i in range(100):
            try:
                file_path = os.path.abspath(os.path.join(path, target))
                if os.path.exists(file_path):
                    return file_path
                path = os.path.split(path)[0]
                if len(path) <= 1:
                    break
            except Exception:
                break
        if os.path.exists(os.path.join(path, target)):
            return os.path.join(path, target)

    if direction == 'down' or direction == 'both':
        check = ['']
        while len(check) != 0:
            dir = check.pop(0)
            try:
                roster = os.listdir(os.path.join(from_path, dir))
            except Exception:
                continue    # ignore directories that are inaccessible
            if target in roster:
                return os.path.join(from_path, dir, target)
            else:
                stack = [os.path.join(from_path, dir, i)
                         for i in roster if '.' not in i]
                if depth_first:
                    check = stack + check
                else:
                    check += stack

    raise FileNotFoundError("Failed to find file: %s from %s", file, from_path)