diff --git a/src/colab_cli/contents.py b/src/colab_cli/contents.py index 72d6d06..d4d0f63 100644 --- a/src/colab_cli/contents.py +++ b/src/colab_cli/contents.py @@ -13,6 +13,7 @@ # limitations under the License. import base64 +import json from urllib.parse import quote import requests @@ -82,8 +83,9 @@ def download(self, remote_path: str, local_path: str): if fmt == "base64": content_bytes = base64.b64decode(content) + elif fmt == "json": + content_bytes = json.dumps(content, indent=1).encode("utf-8") else: - # Assume text if it's not base64 explicitly encoded content_bytes = str(content).encode("utf-8") with open(local_path, "wb") as f: diff --git a/tests/test_contents.py b/tests/test_contents.py index 4c910c8..713aaff 100644 --- a/tests/test_contents.py +++ b/tests/test_contents.py @@ -13,6 +13,7 @@ # limitations under the License. import base64 +import json from unittest.mock import MagicMock, patch import pytest @@ -123,6 +124,33 @@ def test_download_file(mock_request, client, tmp_path): assert local_file.read_bytes() == content_bytes +@patch("colab_cli.contents.requests.request") +def test_download_json_format_writes_valid_json(mock_request, client, tmp_path): + """Notebooks returned with format=json must be saved as valid JSON, not Python repr.""" + notebook_content = { + "cells": [{"cell_type": "code", "source": ["print('hello')"]}], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5, + } + mock_resp = MagicMock(spec=Response) + mock_resp.status_code = 200 + mock_resp.json.return_value = { + "name": "notebook.ipynb", + "type": "notebook", + "format": "json", + "content": notebook_content, + } + mock_request.return_value = mock_resp + + local_file = tmp_path / "notebook.ipynb" + client.download("content/notebook.ipynb", str(local_file)) + + raw = local_file.read_text("utf-8") + parsed = json.loads(raw) + assert parsed == notebook_content + + @patch("colab_cli.contents.requests.request") def test_upload_file(mock_request, client, tmp_path): mock_resp = MagicMock(spec=Response)