diff --git a/office365/onedrive/driveitems/driveItem.py b/office365/onedrive/driveitems/driveItem.py index 0c31c628b..2c81a9f73 100644 --- a/office365/onedrive/driveitems/driveItem.py +++ b/office365/onedrive/driveitems/driveItem.py @@ -427,7 +427,7 @@ def get_content(self, format_name: str | None = None) -> ClientResult[AnyStr]: action_name = "content" if format_name is not None: action_name = action_name + rf"?format={format_name}" - qry = FunctionQuery(self, action_name, None, return_type) + qry = FunctionQuery(self, action_name, None, return_type, return_raw_content=True) self.context.add_query(qry) return return_type diff --git a/office365/runtime/odata/request.py b/office365/runtime/odata/request.py index 6f3e4980e..d5bc43fbc 100644 --- a/office365/runtime/odata/request.py +++ b/office365/runtime/odata/request.py @@ -77,7 +77,9 @@ def process_response(self, response: Response, query: ClientQuery) -> None: if isinstance(return_type, ClientObject): return_type.clear_state() - if response.headers.get("Content-Type", "").lower().split(";")[0] != "application/json": + content_type = response.headers.get("Content-Type", "").lower().split(";")[0] + + if content_type != "application/json" or self._is_raw_content_query(query): if isinstance(return_type, ClientResult): return_type.set_property("__value", response.content) else: @@ -87,6 +89,11 @@ def process_response(self, response: Response, query: ClientQuery) -> None: self.map_json(response.json(), return_type, json_format) + @staticmethod + def _is_raw_content_query(query: ClientQuery) -> bool: + """Check if the query represents a raw content retrieval (e.g. file download).""" + return isinstance(query, FunctionQuery) and query.return_raw_content + def map_json( self, json: Any, diff --git a/office365/runtime/queries/function.py b/office365/runtime/queries/function.py index 4c1911b3d..726ef9a8f 100644 --- a/office365/runtime/queries/function.py +++ b/office365/runtime/queries/function.py @@ -15,6 +15,7 @@ def __init__( method_name: str | None = None, method_params: list | dict | ClientValue | None = None, return_type: ReturnT | None = None, + return_raw_content: bool = False, ) -> None: """Initialize a function query. @@ -23,9 +24,17 @@ def __init__( method_name: The name of the method to call method_params: Parameters for the method call return_type: The expected return type + return_raw_content: When True, the response body is treated as raw content + (e.g. file download) rather than parsed as OData JSON. """ super().__init__(binding_type.context, binding_type, None, None, return_type) self._path = ServiceOperationPath(method_name or "", method_params, binding_type.resource_path) + self._return_raw_content = return_raw_content + + @property + def return_raw_content(self) -> bool: + """Whether the response should be treated as raw content, not OData JSON.""" + return self._return_raw_content def __repr__(self) -> str: return f"FunctionQuery(name={self.path.name})" diff --git a/office365/sharepoint/files/file.py b/office365/sharepoint/files/file.py index 6ba5c0f4a..219d310de 100644 --- a/office365/sharepoint/files/file.py +++ b/office365/sharepoint/files/file.py @@ -140,7 +140,7 @@ def _file_loaded(): def get_content(self) -> ClientResult[bytes]: """Downloads a file content""" return_type = ClientResult(self.context, bytes()) - qry = FunctionQuery(self, "$value", return_type=return_type) + qry = FunctionQuery(self, "$value", return_type=return_type, return_raw_content=True) self.context.add_query(qry) return return_type