msgraphfs 0.4__tar.gz → 0.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {msgraphfs-0.4 → msgraphfs-0.5}/PKG-INFO +5 -1
- {msgraphfs-0.4 → msgraphfs-0.5}/README.md +4 -0
- {msgraphfs-0.4 → msgraphfs-0.5}/src/msgraphfs/core.py +35 -19
- {msgraphfs-0.4 → msgraphfs-0.5}/.gitignore +0 -0
- {msgraphfs-0.4 → msgraphfs-0.5}/LICENSE +0 -0
- {msgraphfs-0.4 → msgraphfs-0.5}/pyproject.toml +0 -0
- {msgraphfs-0.4 → msgraphfs-0.5}/src/msgraphfs/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: msgraphfs
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5
|
|
4
4
|
Dynamic: Summary
|
|
5
5
|
Project-URL: Source, https://github.com/acsone/msgraphfs
|
|
6
6
|
Author-email: Laurent Mignon <laurent.mignon@acsone.eu>
|
|
@@ -230,3 +230,7 @@ To use this filesystem, you need to register an Azure AD application:
|
|
|
230
230
|
6. Note the Application (client) ID, Directory (tenant) ID, and client secret
|
|
231
231
|
|
|
232
232
|
The filesystem uses the OAuth2 client credentials flow with the default scope (`https://graph.microsoft.com/.default`), which automatically includes all application permissions granted to your Azure AD application.
|
|
233
|
+
|
|
234
|
+
### Running the tests
|
|
235
|
+
|
|
236
|
+
See [TESTING.md](TESTING.md) for how to run the test suite, including the live tests against a real SharePoint site.
|
|
@@ -184,3 +184,7 @@ To use this filesystem, you need to register an Azure AD application:
|
|
|
184
184
|
6. Note the Application (client) ID, Directory (tenant) ID, and client secret
|
|
185
185
|
|
|
186
186
|
The filesystem uses the OAuth2 client credentials flow with the default scope (`https://graph.microsoft.com/.default`), which automatically includes all application permissions granted to your Azure AD application.
|
|
187
|
+
|
|
188
|
+
### Running the tests
|
|
189
|
+
|
|
190
|
+
See [TESTING.md](TESTING.md) for how to run the test suite, including the live tests against a real SharePoint site.
|
|
@@ -64,6 +64,15 @@ def parse_range_header(range_header):
|
|
|
64
64
|
raise ValueError("Invalid Range header format")
|
|
65
65
|
|
|
66
66
|
|
|
67
|
+
def split_parent_child(path: str) -> tuple[str, str]:
|
|
68
|
+
"""Split a path into its parent path and its final component.
|
|
69
|
+
|
|
70
|
+
If ``path`` has no ``/`` separator, the parent is the empty string
|
|
71
|
+
(i.e. the item is considered a direct child of the root).
|
|
72
|
+
"""
|
|
73
|
+
return path.rsplit("/", 1) if "/" in path else ("", path)
|
|
74
|
+
|
|
75
|
+
|
|
67
76
|
def parse_msgraph_url(url_path): # noqa: C901
|
|
68
77
|
"""Parse a msgraph URL to extract site_name, drive_name, and path.
|
|
69
78
|
|
|
@@ -655,7 +664,7 @@ class AbstractMSGraphFS(AsyncFileSystem):
|
|
|
655
664
|
path1, item_id=source_item_id, action="copy"
|
|
656
665
|
)
|
|
657
666
|
path2 = self._strip_protocol(path2)
|
|
658
|
-
parent_path, _file_name = path2
|
|
667
|
+
parent_path, _file_name = split_parent_child(path2)
|
|
659
668
|
item_reference = await self._get_item_reference(parent_path)
|
|
660
669
|
json = {
|
|
661
670
|
"parentReference": item_reference,
|
|
@@ -721,7 +730,6 @@ class AbstractMSGraphFS(AsyncFileSystem):
|
|
|
721
730
|
For example, if you want to expand the properties to include the thumbnails,
|
|
722
731
|
you can pass "thumbnails" as the value of the expand parameter.
|
|
723
732
|
"""
|
|
724
|
-
|
|
725
733
|
url = await self._path_to_url_async(path, item_id=item_id)
|
|
726
734
|
params = {}
|
|
727
735
|
if expand:
|
|
@@ -729,7 +737,7 @@ class AbstractMSGraphFS(AsyncFileSystem):
|
|
|
729
737
|
response = await self._msgraph_get(url, params=params)
|
|
730
738
|
return self._drive_item_info_to_fsspec_info(response.json())
|
|
731
739
|
|
|
732
|
-
async def _ls(
|
|
740
|
+
async def _ls( # noqa: C901
|
|
733
741
|
self,
|
|
734
742
|
path: str,
|
|
735
743
|
detail: bool = True,
|
|
@@ -768,13 +776,21 @@ class AbstractMSGraphFS(AsyncFileSystem):
|
|
|
768
776
|
params = {"select": "name,parentReference"}
|
|
769
777
|
if expand:
|
|
770
778
|
params = {"expand": expand}
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
while "@odata.nextLink" in result:
|
|
775
|
-
response = await self._msgraph_get(result["@odata.nextLink"])
|
|
779
|
+
items = []
|
|
780
|
+
try:
|
|
781
|
+
response = await self._msgraph_get(url, params=params)
|
|
776
782
|
result = response.json()
|
|
777
|
-
items
|
|
783
|
+
items = result.get("value", [])
|
|
784
|
+
while "@odata.nextLink" in result:
|
|
785
|
+
response = await self._msgraph_get(result["@odata.nextLink"])
|
|
786
|
+
result = response.json()
|
|
787
|
+
items.extend(result.get("value", []))
|
|
788
|
+
except HTTPStatusError as e:
|
|
789
|
+
if (
|
|
790
|
+
not e.response.status_code == 422
|
|
791
|
+
and "getChildrenOnNonFolder" not in e.response.content
|
|
792
|
+
):
|
|
793
|
+
raise e
|
|
778
794
|
if not items:
|
|
779
795
|
# maybe the path is a file
|
|
780
796
|
try:
|
|
@@ -891,7 +907,7 @@ class AbstractMSGraphFS(AsyncFileSystem):
|
|
|
891
907
|
|
|
892
908
|
async def _mkdir(self, path, create_parents=True, exist_ok=False, **kwargs) -> str:
|
|
893
909
|
path = self._strip_protocol(path).rstrip("/")
|
|
894
|
-
parent, child = path
|
|
910
|
+
parent, child = split_parent_child(path)
|
|
895
911
|
parent_id = await self._get_item_id(parent)
|
|
896
912
|
if not parent_id and not create_parents:
|
|
897
913
|
raise FileNotFoundError(f"Parent directory does not exists: {parent}")
|
|
@@ -961,7 +977,7 @@ class AbstractMSGraphFS(AsyncFileSystem):
|
|
|
961
977
|
if destination_item_id:
|
|
962
978
|
item_reference = await self._get_item_reference(path2)
|
|
963
979
|
else:
|
|
964
|
-
parent_path, name = path2
|
|
980
|
+
parent_path, name = split_parent_child(path2)
|
|
965
981
|
item_reference = await self._get_item_reference(parent_path)
|
|
966
982
|
json = {
|
|
967
983
|
"parentReference": item_reference,
|
|
@@ -1071,7 +1087,7 @@ class AbstractMSGraphFS(AsyncFileSystem):
|
|
|
1071
1087
|
url, json={"lastModifiedDateTime": datetime.now().isoformat()}
|
|
1072
1088
|
)
|
|
1073
1089
|
else:
|
|
1074
|
-
parent_path, file_name = path
|
|
1090
|
+
parent_path, file_name = split_parent_child(path)
|
|
1075
1091
|
parent_id = await self._get_item_id(parent_path, throw_on_missing=True)
|
|
1076
1092
|
item_id = f"{parent_id}:/{file_name}:"
|
|
1077
1093
|
url = await self._path_to_url_async(path, item_id=item_id, action="content")
|
|
@@ -1095,7 +1111,6 @@ class AbstractMSGraphFS(AsyncFileSystem):
|
|
|
1095
1111
|
refresh : bool (=False)
|
|
1096
1112
|
if False, look in local cache for file details first
|
|
1097
1113
|
"""
|
|
1098
|
-
|
|
1099
1114
|
info = await self._info(path, refresh=refresh)
|
|
1100
1115
|
|
|
1101
1116
|
if info["type"] != "directory":
|
|
@@ -1766,12 +1781,13 @@ class MSGDriveFS(AbstractMSGraphFS):
|
|
|
1766
1781
|
}
|
|
1767
1782
|
|
|
1768
1783
|
async def _get_recycle_bin_items(self) -> list[dict]:
|
|
1769
|
-
"""Get the items in the recycle bin.
|
|
1784
|
+
"""Get the items in the recycle bin.
|
|
1770
1785
|
|
|
1771
|
-
|
|
1772
|
-
|
|
1786
|
+
(Beta!!)
|
|
1787
|
+
Returns:
|
|
1788
|
+
list[dict]: A list of dictionaries with information about the items in the recycle bin.
|
|
1773
1789
|
|
|
1774
|
-
|
|
1790
|
+
see https://docs.microsoft.com/en-us/graph/api/resources/driveitem?view=graph-rest-1.0
|
|
1775
1791
|
"""
|
|
1776
1792
|
site_id = await self._get_site_id()
|
|
1777
1793
|
url = f"https://graph.microsoft.com/beta/sites/{site_id}/recycleBin/items"
|
|
@@ -1904,7 +1920,7 @@ class AsyncStreamedFileMixin:
|
|
|
1904
1920
|
"""
|
|
1905
1921
|
item_id = await self.item_id
|
|
1906
1922
|
if not item_id:
|
|
1907
|
-
parent_path, file_name = self.path
|
|
1923
|
+
parent_path, file_name = split_parent_child(self.path)
|
|
1908
1924
|
parent_id = await self.fs._get_item_id(parent_path)
|
|
1909
1925
|
item_id = f"{parent_id}:/{file_name}:"
|
|
1910
1926
|
url = self.fs._path_to_url(
|
|
@@ -1944,7 +1960,7 @@ class AsyncStreamedFileMixin:
|
|
|
1944
1960
|
headers["content-type"] = self.fs._guess_type(self.path)
|
|
1945
1961
|
item_id = await self.item_id
|
|
1946
1962
|
if not item_id:
|
|
1947
|
-
parent_path, file_name = self.path
|
|
1963
|
+
parent_path, file_name = split_parent_child(self.path)
|
|
1948
1964
|
parent_id = await self.fs._get_item_id(parent_path, throw_on_missing=True)
|
|
1949
1965
|
item_id = f"{parent_id}:/{file_name}:"
|
|
1950
1966
|
url = self.fs._path_to_url(self.path, item_id=item_id, action="content")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|