diff --git a/minimax_mcp/utils.py b/minimax_mcp/utils.py index 0cfdfdf..acee8dc 100644 --- a/minimax_mcp/utils.py +++ b/minimax_mcp/utils.py @@ -12,8 +12,17 @@ def is_file_writeable(path: Path) -> bool: if path.exists(): return os.access(path, os.W_OK) - parent_dir = path.parent - return os.access(parent_dir, os.W_OK) + # The path does not exist yet. Callers create it with + # ``mkdir(parents=True)``, which may create several missing levels, so + # check the nearest existing ancestor (the directory ``mkdir`` will + # actually create entries in) rather than only the immediate parent (which + # is itself missing for a multi-level new path). Creating a child in a + # directory needs both write and search (execute) permission, so check + # ``W_OK | X_OK``. + for ancestor in path.parents: + if ancestor.exists(): + return os.access(ancestor, os.W_OK | os.X_OK) + return False def build_output_file( diff --git a/tests/test_utils.py b/tests/test_utils.py index 13691a1..30503b7 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -16,6 +16,20 @@ def test_is_file_writeable(): temp_path = Path(temp_dir) assert is_file_writeable(temp_path) is True assert is_file_writeable(temp_path / "nonexistent.txt") is True + # Multi-level new path: the immediate parent does not exist yet, but + # mkdir(parents=True) can create it, so it must be reported writeable + # (regression: only the immediate parent used to be checked). + assert is_file_writeable(temp_path / "a" / "b" / "c") is True + + +def test_build_output_path_creates_nested_dir(): + # A nested, not-yet-existing output directory must be created rather than + # rejected as "not writeable". + with tempfile.TemporaryDirectory() as temp_dir: + result = build_output_path("a/b/c", temp_dir) + assert result == Path(temp_dir) / "a" / "b" / "c" + assert result.exists() + assert result.is_dir() def test_make_output_file():