From d515e49263123bad231069ab2ec336e06b683be5 Mon Sep 17 00:00:00 2001 From: Miguel Ferrer Date: Wed, 15 Dec 2021 16:57:16 -0500 Subject: [PATCH 1/2] Improves drive and workbook methods --- microsoftgraph/client.py | 57 +++++++------ microsoftgraph/decorators.py | 11 +++ microsoftgraph/files.py | 36 ++++++-- microsoftgraph/workbooks.py | 156 ++++++++++++++++++----------------- setup.py | 2 +- 5 files changed, 153 insertions(+), 109 deletions(-) diff --git a/microsoftgraph/client.py b/microsoftgraph/client.py index 9344d9a..d409366 100644 --- a/microsoftgraph/client.py +++ b/microsoftgraph/client.py @@ -48,6 +48,7 @@ def __init__( self.base_url = self.RESOURCE + self.api_version + "/" self.token = None + self.workbook_session_id = None self.paginate = paginate self.calendar = Calendar(self) @@ -166,6 +167,14 @@ def set_token(self, token: dict) -> None: """ self.token = token + def set_workbook_session_id(self, workbook_session_id: dict) -> None: + """Sets the Workbook Session Id token for its use in this library. + + Args: + token (dict): Workbook Session ID. + """ + self.workbook_session_id = workbook_session_id + def _paginate_response(self, response: dict, **kwargs) -> dict: """Some queries against Microsoft Graph return multiple pages of data either due to server-side paging or due to the use of the $top query parameter to specifically limit the page size in a request. When a result set spans @@ -180,7 +189,7 @@ def _paginate_response(self, response: dict, **kwargs) -> dict: Returns: dict: Graph API Response. """ - if not self.paginate: + if not self.paginate or not isinstance(response.data, dict): return response while "@odata.nextLink" in response.data: data = response.data["value"] @@ -224,51 +233,51 @@ def _parse(self, response): if status_code in (200, 201, 202, 204, 206): return r elif status_code == 400: - raise exceptions.BadRequest(r) + raise exceptions.BadRequest(r.data) elif status_code == 401: - raise exceptions.Unauthorized(r) + raise exceptions.Unauthorized(r.data) elif status_code == 403: - raise exceptions.Forbidden(r) + raise exceptions.Forbidden(r.data) elif status_code == 404: - raise exceptions.NotFound(r) + raise exceptions.NotFound(r.data) elif status_code == 405: - raise exceptions.MethodNotAllowed(r) + raise exceptions.MethodNotAllowed(r.data) elif status_code == 406: - raise exceptions.NotAcceptable(r) + raise exceptions.NotAcceptable(r.data) elif status_code == 409: - raise exceptions.Conflict(r) + raise exceptions.Conflict(r.data) elif status_code == 410: - raise exceptions.Gone(r) + raise exceptions.Gone(r.data) elif status_code == 411: - raise exceptions.LengthRequired(r) + raise exceptions.LengthRequired(r.data) elif status_code == 412: - raise exceptions.PreconditionFailed(r) + raise exceptions.PreconditionFailed(r.data) elif status_code == 413: - raise exceptions.RequestEntityTooLarge(r) + raise exceptions.RequestEntityTooLarge(r.data) elif status_code == 415: - raise exceptions.UnsupportedMediaType(r) + raise exceptions.UnsupportedMediaType(r.data) elif status_code == 416: - raise exceptions.RequestedRangeNotSatisfiable(r) + raise exceptions.RequestedRangeNotSatisfiable(r.data) elif status_code == 422: - raise exceptions.UnprocessableEntity(r) + raise exceptions.UnprocessableEntity(r.data) elif status_code == 429: - raise exceptions.TooManyRequests(r) + raise exceptions.TooManyRequests(r.data) elif status_code == 500: - raise exceptions.InternalServerError(r) + raise exceptions.InternalServerError(r.data) elif status_code == 501: - raise exceptions.NotImplemented(r) + raise exceptions.NotImplemented(r.data) elif status_code == 503: - raise exceptions.ServiceUnavailable(r) + raise exceptions.ServiceUnavailable(r.data) elif status_code == 504: - raise exceptions.GatewayTimeout(r) + raise exceptions.GatewayTimeout(r.data) elif status_code == 507: - raise exceptions.InsufficientStorage(r) + raise exceptions.InsufficientStorage(r.data) elif status_code == 509: - raise exceptions.BandwidthLimitExceeded(r) + raise exceptions.BandwidthLimitExceeded(r.data) else: if r["error"]["innerError"]["code"] == "lockMismatch": # File is currently locked due to being open in the web browser # while attempting to reupload a new version to the drive. # Thus temporarily unavailable. - raise exceptions.ServiceUnavailable(r) - raise exceptions.UnknownError(r) + raise exceptions.ServiceUnavailable(r.data) + raise exceptions.UnknownError(r.data) diff --git a/microsoftgraph/decorators.py b/microsoftgraph/decorators.py index e2c2469..f59af84 100644 --- a/microsoftgraph/decorators.py +++ b/microsoftgraph/decorators.py @@ -11,3 +11,14 @@ def helper(*args, **kwargs): return func(*args, **kwargs) return helper + + +def workbook_session_id_required(func): + @wraps(func) + def helper(*args, **kwargs): + module = args[0] + if not module._client.workbook_session_id: + raise TokenRequired("You must set the Workbook Session Id.") + return func(*args, **kwargs) + + return helper diff --git a/microsoftgraph/files.py b/microsoftgraph/files.py index 8ffbd9b..5feba13 100644 --- a/microsoftgraph/files.py +++ b/microsoftgraph/files.py @@ -58,8 +58,8 @@ def drive_specific_folder(self, folder_id: str, params: dict = None) -> Response Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/children".format(folder_id) - return self._client._get(url, params=params) + url = "me/drive/items/{}/children".format(folder_id) + return self._client._get(self._client.base_url + url, params=params) @token_required def drive_get_item(self, item_id: str, params: dict = None, **kwargs) -> Response: @@ -75,8 +75,8 @@ def drive_get_item(self, item_id: str, params: dict = None, **kwargs) -> Respons Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}".format(item_id) - return self._client._get(url, params=params, **kwargs) + url = "me/drive/items/{}".format(item_id) + return self._client._get(self._client.base_url + url, params=params, **kwargs) @token_required def drive_download_contents(self, item_id: str, params: dict = None, **kwargs) -> Response: @@ -92,8 +92,8 @@ def drive_download_contents(self, item_id: str, params: dict = None, **kwargs) - Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/content".format(item_id) - return self._client._get(url, params=params, **kwargs) + url = "me/drive/items/{}/content".format(item_id) + return self._client._get(self._client.base_url + url, params=params, **kwargs) @token_required def drive_download_shared_contents(self, share_id: str, params: dict = None, **kwargs) -> Response: @@ -111,7 +111,7 @@ def drive_download_shared_contents(self, share_id: str, params: dict = None, **k """ base64_value = base64.b64encode(share_id.encode()).decode() encoded_share_url = "u!" + base64_value.rstrip("=").replace("/", "_").replace("+", "-") - url = self._client.base_url + "shares/{0}/driveItem".format(encoded_share_url) + url = self._client.base_url + "shares/{}/driveItem".format(encoded_share_url) drive_item = self._client._get(url) file_download_url = drive_item["@microsoft.graph.downloadUrl"] return drive_item["name"], requests.get(file_download_url).content @@ -148,6 +148,24 @@ def drive_upload_item(self, item_id: str, params: dict = None, **kwargs) -> Resp Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/content".format(item_id) kwargs["headers"] = {"Content-Type": "text/plain"} - return self._client._put(url, params=params, **kwargs) + url = "me/drive/items/{}/content".format(item_id) + return self._client._put(self._client.base_url + url, params=params, **kwargs) + + @token_required + def search_items(self, q: str, params: dict = None, **kwargs) -> Response: + """Search the hierarchy of items for items matching a query. You can search within a folder hierarchy, a whole + drive, or files shared with the current user. + + https://docs.microsoft.com/en-us/graph/api/driveitem-search?view=graph-rest-1.0&tabs=http + + Args: + q (str): The query text used to search for items. Values may be matched across several fields including + filename, metadata, and file content. + params (dict, optional): Query. Defaults to None. + + Returns: + Response: Microsoft Graph Response. + """ + url = "me/drive/root/search(q='{}')".format(q) + return self._client._get(self._client.base_url + url, params=params, **kwargs) diff --git a/microsoftgraph/workbooks.py b/microsoftgraph/workbooks.py index 0ba0ffb..3f7ccda 100644 --- a/microsoftgraph/workbooks.py +++ b/microsoftgraph/workbooks.py @@ -1,6 +1,6 @@ from urllib.parse import quote_plus -from microsoftgraph.decorators import token_required +from microsoftgraph.decorators import token_required, workbook_session_id_required from microsoftgraph.response import Response @@ -27,10 +27,11 @@ def create_session(self, workbook_id: str, **kwargs) -> Response: Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/workbook/createSession".format(workbook_id) - return self._client._post(url, **kwargs) + url = "me/drive/items/{}/workbook/createSession".format(workbook_id) + return self._client._post(self._client.base_url + url, **kwargs) @token_required + @workbook_session_id_required def refresh_session(self, workbook_id: str, **kwargs) -> Response: """Refresh an existing workbook session. @@ -42,10 +43,12 @@ def refresh_session(self, workbook_id: str, **kwargs) -> Response: Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/workbook/refreshSession".format(workbook_id) - return self._client._post(url, **kwargs) + headers = {"workbook-session-id": self._client.workbook_session_id} + url = "me/drive/items/{}/workbook/refreshSession".format(workbook_id) + return self._client._post(self._client.base_url + url, headers=headers, **kwargs) @token_required + @workbook_session_id_required def close_session(self, workbook_id: str, **kwargs) -> Response: """Close an existing workbook session. @@ -57,73 +60,72 @@ def close_session(self, workbook_id: str, **kwargs) -> Response: Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/workbook/closeSession".format(workbook_id) - return self._client._post(url, **kwargs) + headers = {"workbook-session-id": self._client.workbook_session_id} + url = "me/drive/items/{}/workbook/closeSession".format(workbook_id) + return self._client._post(self._client.base_url + url, headers=headers, **kwargs) @token_required - def list_worksheets(self, workbook_id: str, params: dict = None, **kwargs) -> Response: - """Retrieve a list of worksheet objects. + def list_names(self, workbook_id: str, params: dict = None, **kwargs) -> Response: + """Retrieve a list of nameditem objects. - https://docs.microsoft.com/en-us/graph/api/workbook-list-worksheets?view=graph-rest-1.0&tabs=http + https://docs.microsoft.com/en-us/graph/api/workbook-list-names?view=graph-rest-1.0&tabs=http Args: - workbook_id (str): Excel file ID. + workbook_id (str): Excel file ID. params (dict, optional): Query. Defaults to None. Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/workbook/worksheets".format(workbook_id) - return self._client._get(url, params=params, **kwargs) + url = "me/drive/items/{}/workbook/names".format(workbook_id) + return self._client._get(self._client.base_url + url, params=params, **kwargs) @token_required - def list_names(self, workbook_id: str, params: dict = None, **kwargs) -> Response: - """Retrieve a list of nameditem objects. + def list_worksheets(self, workbook_id: str, params: dict = None, **kwargs) -> Response: + """Retrieve a list of worksheet objects. - https://docs.microsoft.com/en-us/graph/api/workbook-list-names?view=graph-rest-1.0&tabs=http + https://docs.microsoft.com/en-us/graph/api/workbook-list-worksheets?view=graph-rest-1.0&tabs=http Args: - workbook_id (str): Excel file ID. + workbook_id (str): Excel file ID. params (dict, optional): Query. Defaults to None. Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/workbook/names".format(workbook_id) - return self._client._get(url, params=params, **kwargs) + url = "me/drive/items/{}/workbook/worksheets".format(workbook_id) + return self._client._get(self._client.base_url + url, params=params, **kwargs) @token_required - def add_worksheet(self, workbook_id: str, **kwargs) -> Response: - """Adds a new worksheet to the workbook. + def get_worksheet(self, workbook_id: str, worksheet_id: str, **kwargs) -> Response: + """Retrieve the properties and relationships of worksheet object. - https://docs.microsoft.com/en-us/graph/api/worksheetcollection-add?view=graph-rest-1.0&tabs=http + https://docs.microsoft.com/en-us/graph/api/worksheet-get?view=graph-rest-1.0&tabs=http Args: workbook_id (str): Excel file ID. + worksheet_id (str): Excel worksheet ID. Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/workbook/worksheets/add".format(workbook_id) - return self._client._post(url, **kwargs) + url = "me/drive/items/{}/workbook/worksheets/{}".format(workbook_id, quote_plus(worksheet_id)) + return self._client._get(self._client.base_url + url, **kwargs) @token_required - def get_worksheet(self, workbook_id: str, worksheet_id: str, **kwargs) -> Response: - """Retrieve the properties and relationships of worksheet object. + def add_worksheet(self, workbook_id: str, **kwargs) -> Response: + """Adds a new worksheet to the workbook. - https://docs.microsoft.com/en-us/graph/api/worksheet-get?view=graph-rest-1.0&tabs=http + https://docs.microsoft.com/en-us/graph/api/worksheetcollection-add?view=graph-rest-1.0&tabs=http Args: workbook_id (str): Excel file ID. - worksheet_id (str): Excel worksheet ID. Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/workbook/worksheets/{1}".format( - workbook_id, quote_plus(worksheet_id) - ) - return self._client._get(url, **kwargs) + url = "me/drive/items/{}/workbook/worksheets/add".format(workbook_id) + return self._client._post(self._client.base_url + url, **kwargs) @token_required def update_worksheet(self, workbook_id: str, worksheet_id: str, **kwargs) -> Response: @@ -138,10 +140,8 @@ def update_worksheet(self, workbook_id: str, worksheet_id: str, **kwargs) -> Res Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/workbook/worksheets/{1}".format( - workbook_id, quote_plus(worksheet_id) - ) - return self._client._patch(url, **kwargs) + url = "me/drive/items/{}/workbook/worksheets/{}".format(workbook_id, quote_plus(worksheet_id)) + return self._client._patch(self._client.base_url + url, **kwargs) @token_required def list_charts(self, workbook_id: str, worksheet_id: str, params: dict = None, **kwargs) -> Response: @@ -157,10 +157,8 @@ def list_charts(self, workbook_id: str, worksheet_id: str, params: dict = None, Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/workbook/worksheets/{1}/charts".format( - workbook_id, quote_plus(worksheet_id) - ) - return self._client._get(url, params=params, **kwargs) + url = "me/drive/items/{}/workbook/worksheets/{}/charts".format(workbook_id, quote_plus(worksheet_id)) + return self._client._get(self._client.base_url + url, params=params, **kwargs) @token_required def add_chart(self, workbook_id: str, worksheet_id: str, **kwargs) -> Response: @@ -175,10 +173,8 @@ def add_chart(self, workbook_id: str, worksheet_id: str, **kwargs) -> Response: Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/workbook/worksheets/{1}/charts/add".format( - workbook_id, quote_plus(worksheet_id) - ) - return self._client._post(url, **kwargs) + url = "me/drive/items/{}/workbook/worksheets/{}/charts/add".format(workbook_id, quote_plus(worksheet_id)) + return self._client._post(self._client.base_url + url, **kwargs) @token_required def list_tables(self, workbook_id: str, params: dict = None, **kwargs) -> Response: @@ -193,8 +189,8 @@ def list_tables(self, workbook_id: str, params: dict = None, **kwargs) -> Respon Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/workbook/tables".format(workbook_id) - return self._client._get(url, params=params, **kwargs) + url = "me/drive/items/{}/workbook/tables".format(workbook_id) + return self._client._get(self._client.base_url + url, params=params, **kwargs) @token_required def add_table(self, workbook_id: str, **kwargs) -> Response: @@ -208,11 +204,11 @@ def add_table(self, workbook_id: str, **kwargs) -> Response: Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/workbook/tables/add".format(workbook_id) - return self._client._post(url, **kwargs) + url = "me/drive/items/{}/workbook/tables/add".format(workbook_id) + return self._client._post(self._client.base_url + url, **kwargs) @token_required - def create_column(self, workbook_id: str, worksheet_id: str, table_id: str, **kwargs) -> Response: + def create_table_column(self, workbook_id: str, worksheet_id: str, table_id: str, **kwargs) -> Response: """Create a new TableColumn. https://docs.microsoft.com/en-us/graph/api/table-post-columns?view=graph-rest-1.0&tabs=http @@ -225,13 +221,13 @@ def create_column(self, workbook_id: str, worksheet_id: str, table_id: str, **kw Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/workbook/worksheets/{1}/tables/{2}/columns".format( + url = "me/drive/items/{}/workbook/worksheets/{}/tables/{}/columns".format( workbook_id, quote_plus(worksheet_id), table_id ) - return self._client._post(url, **kwargs) + return self._client._post(self._client.base_url + url, **kwargs) @token_required - def create_row(self, workbook_id: str, worksheet_id: str, table_id: str, **kwargs) -> Response: + def create_table_row(self, workbook_id: str, worksheet_id: str, table_id: str, **kwargs) -> Response: """Adds rows to the end of a table. https://docs.microsoft.com/en-us/graph/api/table-post-rows?view=graph-rest-1.0&tabs=http @@ -244,13 +240,13 @@ def create_row(self, workbook_id: str, worksheet_id: str, table_id: str, **kwarg Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/workbook/worksheets/{1}/tables/{2}/rows".format( + url = "me/drive/items/{}/workbook/worksheets/{}/tables/{}/rows".format( workbook_id, quote_plus(worksheet_id), table_id ) - return self._client._post(url, **kwargs) + return self._client._post(self._client.base_url + url, **kwargs) @token_required - def list_rows(self, workbook_id: str, table_id: str, params: dict = None, **kwargs) -> Response: + def list_table_rows(self, workbook_id: str, table_id: str, params: dict = None, **kwargs) -> Response: """Retrieve a list of tablerow objects. https://docs.microsoft.com/en-us/graph/api/table-list-rows?view=graph-rest-1.0&tabs=http @@ -263,21 +259,11 @@ def list_rows(self, workbook_id: str, table_id: str, params: dict = None, **kwar Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/workbook/tables/{1}/rows".format(workbook_id, table_id) - return self._client._get(url, params=params, **kwargs) - - # @token_required - # def excel_get_cell(self, item_id, worksheet_id, params=None, **kwargs): - # url = self.base_url + "me/drive/items/{0}/workbook/worksheets/{1}/Cell(row='1', column='A')".format(item_id, quote_plus(worksheet_id)) - # return self._get(url, params=params, **kwargs) - - # @token_required - # def excel_add_cell(self, item_id, worksheet_id, **kwargs): - # url = self.base_url + "me/drive/items/{0}/workbook/worksheets/{1}/rows".format(item_id, worksheet_id) - # return self._patch(url, **kwargs) + url = "me/drive/items/{}/workbook/tables/{}/rows".format(workbook_id, table_id) + return self._client._get(self._client.base_url + url, params=params, **kwargs) @token_required - def get_range(self, workbook_id: str, worksheet_id: str, **kwargs) -> Response: + def get_range(self, workbook_id: str, worksheet_id: str, address: str, **kwargs) -> Response: """Gets the range object specified by the address or name. https://docs.microsoft.com/en-us/graph/api/worksheet-range?view=graph-rest-1.0&tabs=http @@ -285,17 +271,36 @@ def get_range(self, workbook_id: str, worksheet_id: str, **kwargs) -> Response: Args: workbook_id (str): Excel file ID. worksheet_id (str): Excel worksheet ID. + address (str): Address. Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/workbook/worksheets/{1}/range(address='A1:B2')".format( - workbook_id, quote_plus(worksheet_id) + url = "me/drive/items/{}/workbook/worksheets/{}/range(address='{}')".format( + workbook_id, quote_plus(worksheet_id), address ) - return self._client._get(url, **kwargs) + return self._client._get(self._client.base_url + url, **kwargs) + + @token_required + def get_used_range(self, workbook_id: str, worksheet_id: str, **kwargs) -> Response: + """The used range is the smallest range that encompasses any cells that have a value or formatting assigned to + them. If the worksheet is blank, this function will return the top left cell. + + https://docs.microsoft.com/en-us/graph/api/worksheet-usedrange?view=graph-rest-1.0&tabs=http + + Args: + workbook_id (str): Excel file ID. + worksheet_id (str): Excel worksheet ID. + + Returns: + Response: Microsoft Graph Response. + """ + url = "me/drive/items/{}/workbook/worksheets/{}/usedRange".format(workbook_id, quote_plus(worksheet_id)) + + return self._client._get(self._client.base_url + url, **kwargs) @token_required - def update_range(self, workbook_id: str, worksheet_id: str, **kwargs) -> Response: + def update_range(self, workbook_id: str, worksheet_id: str, address: str, **kwargs) -> Response: """Update the properties of range object. https://docs.microsoft.com/en-us/graph/api/range-update?view=graph-rest-1.0&tabs=http @@ -303,11 +308,12 @@ def update_range(self, workbook_id: str, worksheet_id: str, **kwargs) -> Respons Args: workbook_id (str): Excel file ID. worksheet_id (str): Excel worksheet ID. + address (str): Address. Returns: Response: Microsoft Graph Response. """ - url = self._client.base_url + "me/drive/items/{0}/workbook/worksheets/{1}/range(address='A1:B2')".format( - workbook_id, quote_plus(worksheet_id) + url = "me/drive/items/{}/workbook/worksheets/{}/range(address='{}')".format( + workbook_id, quote_plus(worksheet_id), address ) - return self._client._patch(url, **kwargs) + return self._client._patch(self._client.base_url + url, **kwargs) diff --git a/setup.py b/setup.py index 0bbed7a..21cc954 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ def read(fname): setup( name="microsoftgraph-python", - version="1.0.0", + version="1.1.0", description="API wrapper for Microsoft Graph written in Python", long_description=read("README.md"), url="https://github.com/GearPlug/microsoftgraph-python", From cf6dc1a19be7a19cae8c9363e44d701b81b94c38 Mon Sep 17 00:00:00 2001 From: Miguel Ferrer Date: Mon, 20 Dec 2021 14:31:41 -0500 Subject: [PATCH 2/2] Validates session workbook for update_range method --- microsoftgraph/workbooks.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/microsoftgraph/workbooks.py b/microsoftgraph/workbooks.py index 3f7ccda..3f80503 100644 --- a/microsoftgraph/workbooks.py +++ b/microsoftgraph/workbooks.py @@ -296,10 +296,10 @@ def get_used_range(self, workbook_id: str, worksheet_id: str, **kwargs) -> Respo Response: Microsoft Graph Response. """ url = "me/drive/items/{}/workbook/worksheets/{}/usedRange".format(workbook_id, quote_plus(worksheet_id)) - return self._client._get(self._client.base_url + url, **kwargs) @token_required + @workbook_session_id_required def update_range(self, workbook_id: str, worksheet_id: str, address: str, **kwargs) -> Response: """Update the properties of range object. @@ -313,7 +313,8 @@ def update_range(self, workbook_id: str, worksheet_id: str, address: str, **kwar Returns: Response: Microsoft Graph Response. """ + headers = {"workbook-session-id": self._client.workbook_session_id} url = "me/drive/items/{}/workbook/worksheets/{}/range(address='{}')".format( workbook_id, quote_plus(worksheet_id), address ) - return self._client._patch(self._client.base_url + url, **kwargs) + return self._client._patch(self._client.base_url + url, headers=headers, **kwargs)