Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions lean/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,17 @@ def _download_modules_json() -> None:
res = get(url, timeout=5)
if res.ok:
from json import dump
# Decode the response and write a temporary file first, so a malformed response
# or a failed write leaves the existing file untouched.
data = res.json()
file_path.parent.mkdir(parents=True, exist_ok=True)
with open(file_path, 'w', encoding='utf-8') as f:
dump(res.json(), f, ensure_ascii=False, indent=4)
temporary_file_path = file_path.with_name(file_path.name + ".tmp")
try:
with open(temporary_file_path, 'w', encoding='utf-8') as f:
dump(data, f, ensure_ascii=False, indent=4)
temporary_file_path.replace(file_path)
finally:
temporary_file_path.unlink(missing_ok=True)
else:
res.raise_for_status()

Expand Down
44 changes: 44 additions & 0 deletions tests/models/test_download_modules_json.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import json
from pathlib import Path

import pytest
from requests.exceptions import JSONDecodeError
from responses import RequestsMock

import lean.models as models


def _write_cache(path: Path) -> str:
content = json.dumps({"modules": {"SavedModule": {"version": "1.0"}}})
path.write_text(content, encoding="utf-8")
return content


def test_download_modules_json_keeps_cache_when_response_is_not_json(requests_mock: RequestsMock,
monkeypatch: pytest.MonkeyPatch) -> None:
cache = Path.cwd() / "cache" / "modules.json"
cache.parent.mkdir()
content = _write_cache(cache)
monkeypatch.setattr(models, "file_path", cache)
requests_mock.add(requests_mock.GET, models.url, body="not json", status=200)

with pytest.raises(JSONDecodeError):
models._download_modules_json()

assert cache.read_text(encoding="utf-8") == content
assert [p.name for p in cache.parent.iterdir()] == ["modules.json"]


def test_download_modules_json_replaces_cache_with_valid_response(requests_mock: RequestsMock,
monkeypatch: pytest.MonkeyPatch) -> None:
cache = Path.cwd() / "cache" / "modules.json"
cache.parent.mkdir()
_write_cache(cache)
monkeypatch.setattr(models, "file_path", cache)
new_modules = {"modules": {"NewModule": {"version": "2.0"}}}
requests_mock.add(requests_mock.GET, models.url, json=new_modules, status=200)

models._download_modules_json()

assert json.loads(cache.read_text(encoding="utf-8")) == new_modules
assert [p.name for p in cache.parent.iterdir()] == ["modules.json"]
Loading