From 4170b2590819982bcd5a941c51728c0ad6f90dbe Mon Sep 17 00:00:00 2001 From: mikemikimike <13286568797@163.com> Date: Tue, 18 Aug 2026 21:00:45 +0800 Subject: [PATCH] fix: support Windows filesystem paths --- open_terminal/main.py | 4 +++- open_terminal/utils/fs.py | 2 +- tests/test_windows_compatibility.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 tests/test_windows_compatibility.py diff --git a/open_terminal/main.py b/open_terminal/main.py index 5d8f2e7..f711856 100644 --- a/open_terminal/main.py +++ b/open_terminal/main.py @@ -650,7 +650,9 @@ async def view_file( ) async def serve_file(path: str, fs: UserFS = Depends(get_filesystem)): """Path-based alias for view_file — enables relative URL resolution in iframes.""" - return await view_file(path=f"/{path}", fs=fs) + if not (path.startswith("/") or (len(path) >= 2 and path[1] == ":")): + path = f"/{path}" + return await view_file(path=path, fs=fs) @app.post( diff --git a/open_terminal/utils/fs.py b/open_terminal/utils/fs.py index acb79da..afe8d5a 100644 --- a/open_terminal/utils/fs.py +++ b/open_terminal/utils/fs.py @@ -192,7 +192,7 @@ def _is_writable_sync(self, path: str) -> bool: pass try: return os.access(path, os.W_OK, effective_ids=True) - except TypeError: + except (TypeError, NotImplementedError): return os.access(path, os.W_OK) async def is_writable(self, path: str) -> bool: diff --git a/tests/test_windows_compatibility.py b/tests/test_windows_compatibility.py new file mode 100644 index 0000000..28b9e20 --- /dev/null +++ b/tests/test_windows_compatibility.py @@ -0,0 +1,29 @@ +import os +from unittest.mock import AsyncMock, patch + +import pytest + +os.environ.setdefault("OPEN_TERMINAL_API_KEY", "test-key") + +from open_terminal.main import serve_file +from open_terminal.utils.fs import UserFS + + +@pytest.mark.asyncio +async def test_serve_file_preserves_windows_drive_path(): + filesystem = object() + with patch("open_terminal.main.view_file", new_callable=AsyncMock) as view_file: + await serve_file("C:/Users/test/index.html", filesystem) + + view_file.assert_awaited_once_with(path="C:/Users/test/index.html", fs=filesystem) + + +def test_is_writable_falls_back_when_effective_ids_are_unsupported(): + filesystem = UserFS(home="C:/Users/test") + path = "C:/Users/test" + + with patch.object(os, "access", side_effect=[NotImplementedError, True]) as access: + assert filesystem._is_writable_sync(path) is True + + assert access.call_count == 2 + assert access.call_args_list[1].kwargs == {}