Skip to content

Commit dd08028

Browse files
committed
OneDrive API : fix for shared path addressing (#801)
1 parent 40ae03a commit dd08028

File tree

15 files changed

+143
-38
lines changed

15 files changed

+143
-38
lines changed

examples/onedrive/files/get_by_abs_url.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from tests import test_team_site_url
66
from tests.graph_case import acquire_token_by_username_password
77

8-
file_abs_url = "{0}/Shared Documents/big_buck_bunny.mp4".format(test_team_site_url)
8+
file_abs_url = "{0}/Shared Documents/Financial Sample.xlsx".format(test_team_site_url)
99

1010
client = GraphClient(acquire_token_by_username_password)
1111
file_item = client.shares.by_url(file_abs_url).drive_item.get().execute_query()
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
"""
2+
Get workbook
3+
"""
4+
from office365.graph_client import GraphClient
5+
from tests import test_team_site_url
6+
from tests.graph_case import acquire_token_by_username_password
7+
8+
file_abs_url = "{0}/Shared Documents/Financial Sample.xlsx".format(test_team_site_url)
9+
10+
client = GraphClient(acquire_token_by_username_password)
11+
drive_item = client.shares.by_url(file_abs_url).drive_item.get().execute_query()
12+
worksheets = drive_item.workbook.worksheets.get().execute_query()
13+
for ws in worksheets:
14+
print(ws)

examples/onenote/__init__.py

Whitespace-only changes.

examples/onenote/create_notebook.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""
22
Demonstrates how to create a new OneNote notebook
33
4-
https://learn.microsoft.com/en-us/graph/api/onenote-post-notebooks?view=graph-rest-1.0&tabs=http
4+
https://learn.microsoft.com/en-us/graph/api/onenote-post-notebooks?view=graph-rest-1.0
55
"""
66

77
from office365.graph_client import GraphClient

office365/directory/applications/template.py

+5-8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import Optional
2+
13
from office365.entity import Entity
24
from office365.runtime.client_result import ClientResult
35
from office365.runtime.queries.service_operation import ServiceOperationQuery
@@ -25,11 +27,8 @@ def instantiate(self, display_name):
2527

2628
@property
2729
def display_name(self):
28-
"""
29-
The name of the application.
30-
31-
:rtype: str or None
32-
"""
30+
# type: () -> Optional[str]
31+
"""The name of the application."""
3332
return self.properties.get("displayName", None)
3433

3534
@property
@@ -44,9 +43,7 @@ def categories(self):
4443

4544
@property
4645
def supported_provisioning_types(self):
47-
"""
48-
The list of provisioning modes supported by this application
49-
"""
46+
"""The list of provisioning modes supported by this application"""
5047
return self.properties.get("supportedProvisioningTypes", StringCollection())
5148

5249
@property

office365/directory/protection/riskyusers/history_item.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import Optional
2+
13
from office365.directory.protection.riskyusers.activity import RiskUserActivity
24
from office365.directory.protection.riskyusers.risky_user import RiskyUser
35

@@ -13,7 +15,6 @@ def activity(self):
1315

1416
@property
1517
def initiated_by(self):
16-
"""The ID of actor that does the operation.
17-
:rtype: str
18-
"""
18+
# type: () -> Optional[str]
19+
"""The ID of actor that does the operation."""
1920
return self.properties.get("initiatedBy", None)

office365/onedrive/driveitems/driveItem.py

+6
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,12 @@ def subscriptions(self):
795795
),
796796
)
797797

798+
def set_property(self, name, value, persist_changes=True):
799+
super(DriveItem, self).set_property(name, value, persist_changes)
800+
if name == "parentReference":
801+
self._resource_path.parent.patch(self.parent_reference.driveId)
802+
return self
803+
798804
def get_property(self, name, default_value=None):
799805
# type: (str, P_T) -> P_T
800806
if default_value is None:
+10-5
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
11
import base64
22

33
from office365.runtime.paths.resource_path import ResourcePath
4+
from office365.runtime.paths.v4.entity import EntityPath
45

56

67
def _url_to_shared_token(url):
7-
"""
8-
Converts url into shared token
9-
:param str url:
10-
"""
8+
# type: (str) -> str
9+
"""Converts url into shared token"""
1110
value = base64.b64encode(url.encode("ascii")).decode("ascii")
1211
if value.endswith("="):
1312
value = value[:-1]
1413
return "u!" + value.replace("/", "_").replace("+", "-")
1514

1615

17-
class SharedPath(ResourcePath):
16+
class SharedPath(EntityPath):
1817
"""Shared token path"""
1918

19+
def patch(self, key):
20+
self._key = "items"
21+
self._parent = ResourcePath(key, ResourcePath("drives"))
22+
self.__class__ = ResourcePath
23+
return self
24+
2025
@property
2126
def segment(self):
2227
return _url_to_shared_token(self._key)

office365/onedrive/shares/drive_item.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from office365.onedrive.permissions.permission import Permission
99
from office365.onedrive.sites.site import Site
1010
from office365.runtime.paths.resource_path import ResourcePath
11+
from office365.runtime.paths.v4.entity import EntityPath
1112

1213

1314
class SharedDriveItem(BaseItem):
@@ -47,7 +48,7 @@ def drive_item(self):
4748
"""Used to access the underlying driveItem"""
4849
return self.properties.get(
4950
"driveItem",
50-
DriveItem(self.context, ResourcePath("driveItem", self.resource_path)),
51+
DriveItem(self.context, EntityPath("driveItem", self.resource_path)),
5152
)
5253

5354
@property

office365/onedrive/workbooks/names/named_item.py

+18-6
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,36 @@
1+
from typing import Optional
2+
13
from office365.entity import Entity
4+
from office365.onedrive.workbooks.ranges.range import WorkbookRange
25
from office365.runtime.paths.resource_path import ResourcePath
6+
from office365.runtime.queries.function import FunctionQuery
37

48

59
class WorkbookNamedItem(Entity):
610
"""Represents a defined name for a range of cells or value. Names can be primitive named objects
711
(as seen in the type below), range object, reference to a range. This object can be used to obtain range
812
object associated with names."""
913

14+
def range(self):
15+
"""Returns the range object that is associated with the name. Throws an exception if the named item's type
16+
isn't a range."""
17+
return_type = WorkbookRange(
18+
self.context, ResourcePath("range", self.resource_path)
19+
)
20+
qry = FunctionQuery(self, "range", return_type=return_type)
21+
self.context.add_query(qry)
22+
return return_type
23+
1024
@property
1125
def name(self):
12-
"""The name of the object. Read-only.
13-
:rtype str or None
14-
"""
26+
# type: () -> Optional[str]
27+
"""The name of the object."""
1528
return self.properties.get("name", None)
1629

1730
@property
1831
def comment(self):
19-
"""Represents the comment associated with this name.
20-
:rtype str or None
21-
"""
32+
# type: () -> Optional[str]
33+
"""Represents the comment associated with this name."""
2234
return self.properties.get("comment", None)
2335

2436
@property

office365/onedrive/workbooks/ranges/range.py

+53-2
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,55 @@
1-
from typing import Optional
1+
from typing import List, Optional
22

33
from office365.entity import Entity
44
from office365.onedrive.workbooks.ranges.format import WorkbookRangeFormat
55
from office365.onedrive.workbooks.ranges.sort import WorkbookRangeSort
66
from office365.onedrive.workbooks.ranges.view import WorkbookRangeView
77
from office365.runtime.paths.resource_path import ResourcePath
88
from office365.runtime.queries.function import FunctionQuery
9+
from office365.runtime.queries.service_operation import ServiceOperationQuery
910

1011

1112
class WorkbookRange(Entity):
1213
"""Range represents a set of one or more contiguous cells such as a cell, a row, a column, block of cells, etc."""
1314

15+
def cell(self, row, column):
16+
"""
17+
Gets the range object containing the single cell based on row and column numbers. The cell can be outside
18+
the bounds of its parent range, so long as it's stays within the worksheet grid.
19+
:param int row: Row number of the cell to be retrieved. Zero-indexed.
20+
:param int column: Column number of the cell to be retrieved. Zero-indexed.
21+
"""
22+
return_type = WorkbookRange(self.context)
23+
params = {"row": row, "column": column}
24+
qry = FunctionQuery(self, "cell", params, return_type=return_type)
25+
self.context.add_query(qry)
26+
return return_type
27+
28+
def clear(self, apply_to=None):
29+
"""Clear range values such as format, fill, and border.
30+
:param str apply_to:
31+
"""
32+
payload = {"applyTo": apply_to}
33+
qry = ServiceOperationQuery(self, "clear", parameters_type=payload)
34+
self.context.add_query(qry)
35+
return self
36+
37+
def insert(self, shift):
38+
"""
39+
Inserts a cell or a range of cells into the worksheet in place of this range, and shifts the other cells to
40+
make space. Returns a new Range object at the now blank space.
41+
:param str shift: Specifies which way to shift the cells. The possible values are: Down, Right.
42+
"""
43+
return_type = WorkbookRange(self.context)
44+
payload = {"shift": shift}
45+
qry = ServiceOperationQuery(
46+
self, "insert", parameters_type=payload, return_type=return_type
47+
)
48+
self.context.add_query(qry)
49+
return return_type
50+
1451
def visible_view(self):
15-
""""""
52+
"""Get the range visible from a filtered range."""
1653
return_type = WorkbookRangeView(self.context)
1754
qry = FunctionQuery(self, "visibleView", return_type=return_type)
1855
self.context.add_query(qry)
@@ -63,6 +100,20 @@ def sort(self):
63100
WorkbookRangeSort(self.context, ResourcePath("sort", self.resource_path)),
64101
)
65102

103+
@property
104+
def values(self):
105+
# type: () -> List
106+
"""Represents the raw values of the specified range. The data returned could be of type string, number,
107+
or a boolean. Cell that contains an error returns the error string."""
108+
return self.properties.get("values", None)
109+
110+
@property
111+
def value_types(self):
112+
# type: () -> List
113+
"""Represents the type of data of each cell. The possible values are:
114+
Unknown, Empty, String, Integer, Double, Boolean, Error."""
115+
return self.properties.get("valueTypes", None)
116+
66117
@property
67118
def worksheet(self):
68119
"""The worksheet containing the current range"""

office365/onedrive/workbooks/tables/table.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,18 @@ class WorkbookTable(Entity):
1818

1919
def data_body_range(self):
2020
"""Gets the range object associated with the data body of the table."""
21-
return_type = WorkbookRange(self.context)
21+
return_type = WorkbookRange(
22+
self.context, ResourcePath("dataBodyRange", self.resource_path)
23+
)
2224
qry = FunctionQuery(self, "dataBodyRange", return_type=return_type)
2325
self.context.add_query(qry)
2426
return return_type
2527

2628
def range(self):
2729
"""Get the range object associated with the entire table."""
28-
return_type = WorkbookRange(self.context)
30+
return_type = WorkbookRange(
31+
self.context, ResourcePath("range", self.resource_path)
32+
)
2933
qry = FunctionQuery(self, "range", return_type=return_type)
3034
self.context.add_query(qry)
3135
return return_type

office365/runtime/paths/v4/entity.py

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
from typing import Optional
2+
3+
from typing_extensions import Self
4+
15
from office365.runtime.paths.resource_path import ResourcePath
26

37

48
class EntityPath(ResourcePath):
59
def __init__(self, key=None, parent=None, collection=None):
6-
"""
7-
:param str or None key: Entity key
8-
:param ResourcePath or None collection:
9-
"""
10+
# type: (Optional[str], Optional[ResourcePath], Optional[ResourcePath]) -> None
1011
super(EntityPath, self).__init__(key, parent)
1112
self._collection = collection
1213

@@ -26,10 +27,8 @@ def segment(self):
2627
return str(self._key or "<key>")
2728

2829
def patch(self, key):
29-
"""
30-
Patches path
31-
:type key: str or None
32-
"""
30+
# type: (str) -> Self
31+
"""Patches the path"""
3332
self._key = key
3433
self._parent = self.collection
3534
self.__class__ = EntityPath

tests/onedrive/test_excel_ranges.py

+15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from office365.onedrive.driveitems.driveItem import DriveItem
22
from office365.onedrive.workbooks.names.named_item import WorkbookNamedItem
3+
from office365.onedrive.workbooks.ranges.range import WorkbookRange
34
from tests import create_unique_name
45
from tests.graph_case import GraphTestCase
56
from tests.onedrive.test_excel import upload_excel
@@ -8,6 +9,7 @@
89
class TestExcelRanges(GraphTestCase):
910
excel_file = None # type: DriveItem
1011
named_item = None # type: WorkbookNamedItem
12+
range = None # type: WorkbookRange
1113
sheet_name = create_unique_name("Sheet")
1214

1315
@classmethod
@@ -30,3 +32,16 @@ def test1_name_create(self):
3032
def test2_names_get(self):
3133
result = self.__class__.named_item.get().execute_query()
3234
self.assertIsNotNone(result.resource_path)
35+
36+
def test3_list_range(self):
37+
result = self.__class__.named_item.range().execute_query()
38+
self.assertIsNotNone(result.address)
39+
self.__class__.range = result
40+
41+
# def test4_insert_range(self):
42+
# result = self.__class__.range.insert("Right").execute_query()
43+
# self.assertIsNotNone(result.address)
44+
45+
def test5_clear_range(self):
46+
result = self.__class__.range.clear().execute_query()
47+
self.assertIsNotNone(result.address)

tests/onedrive/test_permissions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def test7_driveitem_delete_permission(self):
7373
perm_to_delete.delete_object().execute_query()
7474

7575
def test8_driveitem_grant_access(self):
76-
file_abs_url = "{0}/Shared Documents/big_buck_bunny.mp4".format(
76+
file_abs_url = "{0}/Shared Documents/Financial Sample.xlsx".format(
7777
test_team_site_url
7878
)
7979
permissions = (

0 commit comments

Comments
 (0)