Repository: robocorp/rpaframework

Issue:
Keyword `List Files in Sharepoint Site Drive` from lib `RPA.MSGraph` only lists OneDrive Files
See user error report from [Slack](https://robocorp-developers.slack.com/archives/CVBU007LN/p1665671211385859) below:

> reagarding the newly released MSGraph library. I think I might have come across some weird behaviour when working with Sharepoint files:
>
> My task: Download certain files from Sharepoint and work with them locally.
>
> The Issue: First, I am obtaining the Sharepoint site:
>
> ```robotframework
>     ${sp_site}=    Get Sharepoint Site    aconio.sharepoint.com    .../sites/mySite
>     Log    Obtained sharepoint site is: ${sp_site}
> ```
>
> This works as expected. Then, I’m checking which drives are available, which also works:
>
> ```robotframework
>     ${drives}=    List Sharepoint Site Drives    ${sp_site}
>     Log    Obtained drives are: ${drives}
> ```
>
> Now, when trying to list files of one specific Drive using the keyword `List Files In Sharepoint Site Drive`, the list of returned files is a list of files contained in my personal OneDrive, not the list of files within the given Sharepoint Drive. Here’s the code that causes the weird behaviour (Doesn’t matter if a Drive is specified using the `drive_id`, or if the default Drive is used, output is the same):
>
> ```robotframework
>     ${list_of_files}=    List Files In Sharepoint Site Drive
>     ...    site=${sp_site}
>     ...    drive_id=myDrive
>     ...    include_folders=${TRUE}
>     FOR    ${item}    IN    @{list_of_files}
>         Log    ${item}
>     END
> ```
>
> The interesting thing: When obtaining the Drive files by directly using the Python O365 library (through calling the `get_items()` method on the previously retrieved Drive object with `List Sharepoint Site Drives`), the correct files are returned. Here’s the code to that:
>
> ```python
>     def get_items_of_drive(self, drive_obj):
>         drive_items = drive_obj.get_items()
>         for item in drive_items:
>             self.logger.info(f"Drive items: {item}")
> ```
> 


Discussion:

Resolving patch:
diff --git a/packages/main/src/RPA/MSGraph.py b/packages/main/src/RPA/MSGraph.py
--- a/packages/main/src/RPA/MSGraph.py
+++ b/packages/main/src/RPA/MSGraph.py
@@ -190,14 +190,28 @@ def get_drive_instance(
         else:
             return storage.get_default_drive()
 
-    def _parse_drive_param(self, drive: DriveType) -> drive_module.Drive:
+    def _parse_drive_param(
+        self,
+        drive: Optional[DriveType] = None,
+        site: Optional[sharepoint.Site] = None,
+        resource: Optional[str] = None,
+    ) -> drive_module.Drive:
         """Helper function which parses the drive parameter given
-        from a robot.
+        from a robot. If you pass a sharepoint site, it will use
+        that to retrieve the default drive rather than OneDrive.
         """
         if isinstance(drive, drive_module.Drive):
             return drive
+        elif isinstance(drive, str):
+            return (
+                site.get_document_library(drive)
+                if site is not None
+                else self.get_drive_instance(resource, drive)
+            )
+        elif site is not None:
+            return site.get_default_document_library()
         else:
-            return self.get_drive_instance(drive)
+            return self.get_drive_instance(resource)
 
     @keyword
     def get_folder_instance(
@@ -313,16 +327,6 @@ def _download_folder(
         folder.download_contents(to_folder=downloaded_folder)
         return downloaded_folder
 
-    def _get_sharepoint_drive(
-        self, site: sharepoint.Site, drive: Optional[DriveType] = None
-    ) -> drive_module.Drive:
-        """Returns the specified SharePoint drive if any or the default one if none."""
-        drive = self._parse_drive_param(drive)
-        if drive:
-            return site.get_document_library(drive.object_id)
-        else:
-            return site.get_default_document_library()
-
     def _sharepoint_items_into_dict_list(
         self, items_instance: List[sharepoint.SharepointListItem]
     ) -> List[dict]:
@@ -579,17 +583,19 @@ def list_files_in_onedrive_folder(
         target_folder: Union[drive_module.Folder, str, None] = None,
         include_folders: Optional[bool] = False,
         resource: Optional[str] = None,
-        drive_id: Optional[str] = None,
+        drive: Optional[DriveType] = None,
     ) -> List[drive_module.DriveItem]:
         """Returns a list of files from the specified OneDrive folder.
 
         The files returned are ``DriveItem`` objects and they have additional
         properties that can be accessed with dot-notation.
 
-        :param target_folder: Path of the folder in Onedrive_module.
+        :param target_folder: Path of the folder in Onedrive. If none is
+         provided, will return files from the root of Onedrive.
         :param include_folders: Boolean indicating if should return folders as well.
         :param resource: Name of the resource if not using default.
-        :param drive_id: Drive ID if not using default.
+        :param drive: A ``Drive`` object or Drive ID as a string. If not
+         provided, will use the default drive.
         :return: List of DriveItems in the folder.
 
         .. code-block: robotframework
@@ -612,7 +618,7 @@ def list_files_in_onedrive_folder(
                 END
         """
         self._require_authentication()
-        drive_instance = self.get_drive_instance(resource, drive_id)
+        drive_instance = self._parse_drive_param(drive, resource=resource)
         folder = self.get_folder_instance(drive_instance, target_folder)
         items = folder.get_items()
         if include_folders:
@@ -626,9 +632,9 @@ def download_file_from_onedrive(
         to_path: Optional[PathType] = None,
         name: Optional[str] = None,
         resource: Optional[str] = None,
-        drive_id: Optional[str] = None,
+        drive: Optional[DriveType] = None,
     ) -> Path:
-        """Downloads a file from Onedrive_module.
+        """Downloads a file from Onedrive.
 
         The downloaded file will be saved to a local path.
 
@@ -637,7 +643,8 @@ def download_file_from_onedrive(
          defaults to the current directory.
         :param name: New name for the downloaded file, with or without extension.
         :param resource: Name of the resource if not using default.
-        :param drive_id: Drive ID if not using default.
+        :param drive: A ``Drive`` object or Drive ID as a string. If not
+         provided, will use the default drive.
         :return: Path to the downloaded file.
 
         .. code-block: robotframework
@@ -656,7 +663,7 @@ def download_file_from_onedrive(
                 ...    Report.pdf
         """
         self._require_authentication()
-        drive_instance = self.get_drive_instance(resource, drive_id)
+        drive_instance = self._parse_drive_param(drive, resource=resource)
         file_instance = self.get_file_instance(drive_instance, target_file)
         return self._download_file(file_instance, to_path, name)
 
@@ -666,7 +673,7 @@ def download_folder_from_onedrive(
         target_folder: Union[drive_module.Folder, str],
         to_path: Optional[PathType] = None,
         resource: Optional[str] = None,
-        drive_id: Optional[str] = None,
+        drive: Optional[DriveType] = None,
     ) -> Path:
         """Downloads a folder from OneDrive with all of its contents,
         including subfolders.
@@ -678,7 +685,8 @@ def download_folder_from_onedrive(
         :param to_path: Destination folder where the download will be saved to,
          defaults to the current directory.
         :param resource: Name of the resource if not using default.
-        :param drive_id: Drive ID if not using default.
+        :param drive: A ``Drive`` object or Drive ID as a string. If not
+         provided, will use the default drive.
         :return: Path to the downloaded folder.
 
         .. code-block: robotframework
@@ -695,7 +703,7 @@ def download_folder_from_onedrive(
                 ...    /path/to/local/folder
         """
         self._require_authentication()
-        drive_instance = self.get_drive_instance(resource, drive_id)
+        drive_instance = self._parse_drive_param(drive, resource=resource)
         folder_instance = self.get_folder_instance(drive_instance, target_folder)
         return self._download_folder(folder_instance, to_path)
 
@@ -706,7 +714,7 @@ def find_onedrive_file(
         target_folder: Optional[Union[drive_module.Folder, str]] = None,
         include_folders: Optional[bool] = False,
         resource: Optional[str] = None,
-        drive_id: Optional[str] = None,
+        drive: Optional[DriveType] = None,
     ) -> List[drive_module.DriveItem]:
         # pylint: disable=anomalous-backslash-in-string
         """Returns a list of files found in OneDrive based on the search string.
@@ -718,13 +726,14 @@ def find_onedrive_file(
         properties that can be accessed with dot-notation, see
         \`List Files In Onedrive Folder\` for details.
 
-        :param search_string: String used to search for file in Onedrive_module.
+        :param search_string: String used to search for file in Onedrive.
          Values may be matched across several fields including filename,
          metadata, and file content.
         :param target_folder: Folder where to search for files.
         :param include_folders: Boolean indicating if should return folders as well.
         :param resource: Name of the resource if not using default.
-        :param drive_id: Drive ID if not using default.
+        :param drive: A ``Drive`` object or Drive ID as a string. If not
+         provided, will use the default drive.
         :return: List of DriveItems found based on the search string.
 
         .. code-block: robotframework
@@ -734,7 +743,7 @@ def find_onedrive_file(
                 ${files}=    Find Onedrive File    Report.xlsx
         """  # noqa: W605
         self._require_authentication()
-        drive_instance = self.get_drive_instance(resource, drive_id)
+        drive_instance = self._parse_drive_param(drive, resource=resource)
         if target_folder:
             folder = self.get_folder_instance(drive_instance, target_folder)
             items = folder.search(search_string)
@@ -759,6 +768,7 @@ def download_file_from_share_link(
         :param to_path: Destination folder of the downloaded file,
          defaults to the current directory.
         :param name: New name for the downloaded file, with or without extension.
+        :return: The Path to the downloaded file.
 
         .. code-block: robotframework
 
@@ -792,7 +802,7 @@ def upload_file_to_onedrive(
         file_path: str,
         target_folder: Optional[Union[drive_module.Folder, str]] = None,
         resource: Optional[str] = None,
-        drive_id: Optional[str] = None,
+        drive: Optional[DriveType] = None,
     ) -> drive_module.DriveItem:
         # pylint: disable=anomalous-backslash-in-string
         """Uploads a file to the specified OneDrive folder.
@@ -802,9 +812,11 @@ def upload_file_to_onedrive(
         \`List Files In Onedrive Folder\` for details.
 
         :param file_path: Path of the local file being uploaded.
-        :param target_folder: Path of the folder in Onedrive_module.
+        :param target_folder: Path of the folder in Onedrive.
         :param resource: Name of the resource if not using default.
-        :param drive_id: Drive ID if not using default.
+        :param drive: A ``Drive`` object or Drive ID as a string. If not
+         provided, will use the default drive.
+        :return: The newly created DriveItem.
 
         .. code-block: robotframework
 
@@ -815,7 +827,7 @@ def upload_file_to_onedrive(
                 ...    /path/to/folder
         """  # noqa: W605
         self._require_authentication()
-        drive_instance = self.get_drive_instance(resource, drive_id)
+        drive_instance = self._parse_drive_param(drive, resource=resource)
         folder = self.get_folder_instance(drive_instance, target_folder)
         return folder.upload_file(item=file_path)
 
@@ -971,13 +983,14 @@ def list_files_in_sharepoint_site_drive(
         self,
         site: sharepoint.Site,
         include_folders: Optional[bool] = False,
-        drive_id: Optional[str] = None,
+        drive: Optional[DriveType] = None,
+        target_folder: Union[drive_module.Folder, str, None] = None,
     ) -> List[drive_module.DriveItem]:
         # pylint: disable=anomalous-backslash-in-string
-        """List files in the SharePoint Site drive_module.
+        """List files in the SharePoint Site drive.
 
-        If the ``drive_id`` is not set, the default Document Library
-        will be used. The ``drive_id`` can be obtained from the keyword
+        If the ``drive`` is not set, the default Document Library
+        will be used. The ``drive`` can be obtained from the keyword
         \`List Sharepoint Site Drives\`.
 
         The files returned are ``DriveItem`` objects and they have additional
@@ -987,8 +1000,11 @@ def list_files_in_sharepoint_site_drive(
         :param site: Site instance obtained from \`Get Sharepoint Site\`.
         :param include_folders: Boolean indicating if should return folders
          as well.
-        :param drive_id: ID of the desired drive_module.
-        :return: List of DriveItems present in the Site drive_module.
+        :param drive: A ``Drive`` object or Drive ID as a string. If not
+         provided, will use the default drive.
+        :param target_folder: Path of the folder in the Sharepoint drive.
+         If none is provided, will return files from the root of the drive.
+        :return: List of DriveItems present in the Site drive.
 
         .. code-block: robotframework
 
@@ -998,8 +1014,8 @@ def list_files_in_sharepoint_site_drive(
                 ${files}    List Files In Sharepoint Site Drive    ${site}
         """  # noqa: W605
         self._require_authentication()
-        sp_drive = self._get_sharepoint_drive(site, drive_id)
-        folder = self.get_folder_instance(sp_drive)
+        drive = self._parse_drive_param(drive, site=site)
+        folder = self.get_folder_instance(drive, target_folder)
         items = folder.get_items()
         if include_folders:
             return items
@@ -1012,7 +1028,7 @@ def download_file_from_sharepoint(
         site: sharepoint.Site,
         to_path: Optional[PathType] = None,
         name: Optional[str] = None,
-        drive_id: Optional[str] = None,
+        drive: Optional[DriveType] = None,
     ) -> Path:
         # pylint: disable=anomalous-backslash-in-string
         """Downloads file from SharePoint.
@@ -1024,7 +1040,7 @@ def download_file_from_sharepoint(
         :param to_path: Destination folder of the downloaded file,
          defaults to the current directory.
         :param name: New name for the downloaded file, with or without extension.
-        :param drive_id: Drive ID if not using default.
+        :param drive: A ``Drive`` object or a Drive ID as a string.
         :return: Path to the downloaded file.
 
         .. code-block: robotframework
@@ -1045,6 +1061,6 @@ def download_file_from_sharepoint(
                 ...    Report.pdf
         """  # noqa: W605
         self._require_authentication()
-        sp_drive = self._get_sharepoint_drive(site, drive_id)
-        file_instance = self.get_file_instance(sp_drive, target_file)
+        drive = self._parse_drive_param(drive, site=site)
+        file_instance = self.get_file_instance(drive, target_file)
         return self._download_file(file_instance, to_path, name)


Test patch:
diff --git a/packages/main/tests/python/test_msgraph.py b/packages/main/tests/python/test_msgraph.py
--- a/packages/main/tests/python/test_msgraph.py
+++ b/packages/main/tests/python/test_msgraph.py
@@ -901,7 +901,7 @@ def test_list_files_in_sharepoint_drive(
     _patch_multiple_graph_responses(authorized_lib, mocker, mocked_responses)
 
     sp_files = authorized_lib.list_files_in_sharepoint_site_drive(
-        sharepoint_site, drive_id=drive_id
+        sharepoint_site, drive=drive_id
     )
 
     for file in sp_files:
@@ -947,7 +947,7 @@ def test_download_file_from_sharepoint(
     _patch_multiple_graph_responses(authorized_lib, mocker, mocked_responses)
 
     downloaded_file = authorized_lib.download_file_from_sharepoint(
-        file_path, sharepoint_site, target_directory, drive_id
+        file_path, sharepoint_site, target_directory, drive=drive_id
     )
 
     assert downloaded_file