commit 26fdad726c47e0035c79a395634ec57b4c427f0c
parent 17273de0bd13eb691dbf7416c3140b43e11535ac
Author: Steven Atkinson <steven@atkinson.mn>
Date: Tue, 17 Sep 2024 09:40:46 -0700
[BUGFIX] Handle settings on read-only filesystem (#465)
* Handle settings on read-only filesystems
* Cleanup
Diffstat:
6 files changed, 83 insertions(+), 12 deletions(-)
diff --git a/nam/train/core.py b/nam/train/core.py
@@ -982,7 +982,6 @@ def _get_configs(
batch_size: int,
fit_mrstft: bool,
):
-
data_config = _get_data_config(
input_version=input_version,
input_path=input_path,
@@ -1564,13 +1563,13 @@ def validate_data(
for split in Split:
try:
init_dataset(data_config, split)
- pytorch_data_split_validation_dict[split.value] = (
- _PyTorchDataSplitValidation(passed=True, msg=None)
- )
+ pytorch_data_split_validation_dict[
+ split.value
+ ] = _PyTorchDataSplitValidation(passed=True, msg=None)
except DataError as e:
- pytorch_data_split_validation_dict[split.value] = (
- _PyTorchDataSplitValidation(passed=False, msg=str(e))
- )
+ pytorch_data_split_validation_dict[
+ split.value
+ ] = _PyTorchDataSplitValidation(passed=False, msg=str(e))
pytorch_data_validation = _PyTorchDataValidation(
passed=all(v.passed for v in pytorch_data_split_validation_dict.values()),
**pytorch_data_split_validation_dict,
diff --git a/nam/train/gui/_resources/settings.py b/nam/train/gui/_resources/settings.py
@@ -42,13 +42,38 @@ def _get_settings() -> dict:
"""
Make sure that ./settings.json exists; if it does, then read it. If not, empty dict.
"""
-
if not _SETTINGS_JSON_PATH.exists():
- _write_settings({})
- with open(_SETTINGS_JSON_PATH, "r") as fp:
- return json.load(fp)
+ return dict()
+ else:
+ with open(_SETTINGS_JSON_PATH, "r") as fp:
+ return json.load(fp)
+
+
+class _WriteSettings(object):
+ def __init__(self):
+ self._oserror = False
+
+ def __call__(self, *args, **kwargs):
+ if self._oserror:
+ return
+ # Try-catch for Issue 448
+ try:
+ return _write_settings_unsafe(*args, **kwargs)
+ except OSError as e:
+ if "Read-only filesystem" in str(e):
+ print(
+ "Failed to write settings--NAM appears to be installed to a "
+ "read-only filesystem. This is discouraged; consider installing to "
+ "a location with user-level access."
+ )
+ self._oserror = True
+ else:
+ raise e
+
+
+_write_settings = _WriteSettings()
-def _write_settings(obj: dict):
+def _write_settings_unsafe(obj: dict):
with open(_SETTINGS_JSON_PATH, "w") as fp:
json.dump(obj, fp, indent=4)
diff --git a/tests/test_nam/test_train/test_gui/__init__.py b/tests/test_nam/test_train/test_gui/__init__.py
@@ -0,0 +1,3 @@
+# File: __init__.py
+# Created Date: Tuesday September 17th 2024
+# Author: Steven Atkinson (steven@atkinson.mn)
diff --git a/tests/test_nam/test_train/test_gui.py b/tests/test_nam/test_train/test_gui/test_main.py
diff --git a/tests/test_nam/test_train/test_gui/test_resources/__init__.py b/tests/test_nam/test_train/test_gui/test_resources/__init__.py
diff --git a/tests/test_nam/test_train/test_gui/test_resources/test_settings.py b/tests/test_nam/test_train/test_gui/test_resources/test_settings.py
@@ -0,0 +1,44 @@
+# File: test_resources.py
+# Created Date: Tuesday September 17th 2024
+# Author: Steven Atkinson (steven@atkinson.mn)
+
+from contextlib import contextmanager
+from pathlib import Path
+
+import pytest
+
+from nam.train.gui._resources import settings
+
+
+class TestReadOnly(object):
+ """
+ Issue 448
+ """
+
+ @pytest.mark.parametrize("path_key", tuple(pk for pk in settings.PathKey))
+ def test_get_last_path(self, path_key: settings.PathKey):
+ with self._mock_read_only():
+ last_path = settings.get_last_path(path_key)
+ assert last_path is None or isinstance(last_path, Path)
+
+ @pytest.mark.parametrize("path_key", tuple(pk for pk in settings.PathKey))
+ def test_set_last_path(self, path_key: settings.PathKey):
+ path = Path(__file__).parent / Path("dummy.txt")
+ with self._mock_read_only():
+ settings.set_last_path(path_key, path)
+
+ @contextmanager
+ def _mock_read_only(self):
+ def write_settings(*args, **kwargs):
+ raise OSError("Read-only filesystem")
+
+ try:
+ tmp = settings._write_settings_unsafe
+ settings._write_settings_unsafe = write_settings
+ yield
+ finally:
+ settings._write_settings_unsafe = tmp
+
+
+if __name__ == "__main__":
+ pytest.main()