class O365Account():
    def __init__(self,
                 client_id=client_id,
                 client_secret=client_secret,
                 scopes=scopes):
        self.client_id = client_id
        self.client_secret = client_secret
        self.account = Account(credentials=(client_id, client_secret))
        self.authenticate(scopes)

        self.storage = self.account.storage()
        self.drives = self.storage.get_drives()
        self.my_drive = self.storage.get_default_drive(
        )  # or get_drive('drive-id')
        self.root_folder = self.my_drive.get_root_folder()

    def authenticate(self, scopes=scopes):
        result = self.account.authenticate(scopes=scopes)

    def get_drive(self):
        return self.my_drive

    def get_root_folder(self):
        return self.root_folder

    def get_folder_from_path(self, folder_path):
        if folder_path is None:
            return self.my_drive

        subfolders = folder_path.split('/')
        if len(subfolders) == 0:
            return self.my_drive

        items = self.my_drive.get_items()
        for subfolder in subfolders:
            try:
                subfolder_drive = list(
                    filter(lambda x: subfolder in x.name, items))[0]
                items = subfolder_drive.get_items()
            except:
                raise ('Path {} not exist.'.format(folder_path))
        return subfolder_drive

    ''' Upload a file named $filename to onedrive folder named $destination. '''

    def upload_file(self, filename, destination=None):
        folder = self.get_child_folder(self.root_folder, destination)
        print('Uploading file ' + filename)
        folder.upload_file(item=filename)

    ''' Download a file named $filename to local folder named $to_path. '''

    def download_file(self, filename, to_path=None):
        dirname = os.path.dirname(filename)
        basename = os.path.basename(filename)
        folder = self.get_folder_from_path(dirname)
        items = folder.get_items()
        if not os.path.exists(to_path):
            os.makedirs(to_path)
        try:
            file = list(filter(lambda x: basename in x.name, items))[0]
            print('Downloading file ' + filename)
            file.download(to_path, chunk_size=CHUNK_SIZE)
            return True
        except:
            print('File {} not exist.'.format(filename))
            return False

    def _get_child_folder(self, folder, child_folder_name):
        items = folder.get_items()
        child_folder_names = [item.name for item in items if item.is_folder]
        if child_folder_name in child_folder_names:
            return list(filter(lambda x: x.name == child_folder_name,
                               items))[0]
        else:
            return folder.create_child_folder(child_folder_name)

    ''' Get child folder, folder tree from root folder. If child folder not exist, make it. '''

    def get_child_folder(self, folder, child_folder_name):
        child_folder_names = child_folder_name.split('/')
        for _child_folder_name in child_folder_names:
            folder = self._get_child_folder(folder, _child_folder_name)
        return folder

    '''
    Upload entire folder named $folder_name from local to onedrive folder named $destination.
    Keep cloud folder structure as that of local folder.
    '''

    def upload_folder(self, folder_name, destination=None):
        print()
        print('Uploading folder ' + folder_name)
        if destination is None:
            destination = folder_name
        destination_item = self.get_child_folder(self.root_folder, destination)

        for file in os.listdir(folder_name):
            path = os.path.join(folder_name, file)
            if os.path.isfile(path):
                self.upload_file(path, destination)
            else:
                folder = self.get_folder_from_path(destination)
                child_destination = self.get_child_folder(folder, file)
                self.upload_folder(path, os.path.join(destination, file))

    '''
    Download entire folder named $folder_name from cloud to local folder named $to_folder.
    Keep local folder structure as that of cloud folder.
    '''

    def download_folder(self, folder_name, to_folder='.', file_type=None):
        to_folder = os.path.join(to_folder, folder_name)
        self._download_folder(folder_name, to_folder, file_type)

    def _download_folder(self, folder_name, to_folder='.', file_type=None):
        print()
        print('Downloading folder ' + folder_name)
        current_wd = os.getcwd()
        if to_folder is not None and to_folder != '.':
            if not os.path.exists(to_folder):
                os.makedirs(to_folder)
            os.chdir(to_folder)

        if folder_name is None:
            folder = self.get_drive()
        folder = self.get_folder_from_path(folder_name)

        items = folder.get_items()
        if file_type is None:
            file_type = ''
        files = list(
            filter(lambda x: file_type in x.name or x.is_folder, items))

        for file in files:
            file_name = file.name
            abs_path = os.path.join(folder_name, file_name)
            if file.is_file:
                print('Downloading file ' + abs_path)
                file.download(chunk_size=CHUNK_SIZE)
            else:
                child_folder_name = abs_path
                self._download_folder(child_folder_name, file_name, file_type)
        os.chdir(current_wd)
        if item.is_file:
            download_file(item, current_path)


def create_folder(item, current_path):
    folder = os.path.join(current_path, item.name)
    os.makedirs(folder, exist_ok=1)
    print(f"Dossier {item.name} créé avec succès !")
    return folder


def download_file(item, path):
    item.download(to_path=path, chunk_size=None)
    print(f"Fichier {item.name} téléchargé avec succès !")


protocol = MSGraphProtocol(api_version='beta')
credentials = ('7b9c81d7-2c01-4d48-86fc-9a7cd9700b85',
               'cBPj06Vjh_[HNkntI-e6pEf.h1JKn12H')

token_backend = FileSystemTokenBackend(token_path='my_folder',
                                       token_filename='my_token.txt')
account = Account(credentials, protocol=protocol, token_backend=token_backend)
account.authenticate(
    scopes=['basic', 'message_all', 'onedrive_all', 'address_book_all'])

storage = account.storage()
my_drive = storage.get_default_drive()

save_folder(my_drive)
import pandas as pd
from O365 import Account

# Generated on the app registration portal
registered_app_name = 'yourregisteredappname'
registered_app_secret = 'yoursecret'

# File to download, and location to download to
dl_path = '/path/to/download'
f_name = 'myfile.xlsx'

print("Connecting to O365")
account = Account(credentials=(registered_app_name, registered_app_secret),
                  scopes=['files.read', 'user.read', 'offline_access'])

storage = account.storage(
)  # here we get the storage instance that handles all the storage options.

# get the default drive
my_drive = storage.get_default_drive()

print(f"Searching for {f_name}...")
files = my_drive.search(f_name, limit=1)
if files:
    numberDoc = files[0]
    print("... copying to local machine")
    operation = numberDoc.download(to_path=dl_path)
else:
    print("File not found!")
    exit()

print("Reading sheet to dataframe")