diff --git a/python/e2e/testharness/context.py b/python/e2e/testharness/context.py index 8638ba5b..533ee87e 100644 --- a/python/e2e/testharness/context.py +++ b/python/e2e/testharness/context.py @@ -100,16 +100,18 @@ async def configure_for_test(self, test_file: str, test_name: str): await self._proxy.configure(abs_snapshot_path, self.work_dir) # Clear temp directories between tests (but leave them in place) + # Use ignore_errors=True to handle race conditions where files may still + # be written by background processes during cleanup for item in Path(self.home_dir).iterdir(): if item.is_dir(): - shutil.rmtree(item) + shutil.rmtree(item, ignore_errors=True) else: - item.unlink() + item.unlink(missing_ok=True) for item in Path(self.work_dir).iterdir(): if item.is_dir(): - shutil.rmtree(item) + shutil.rmtree(item, ignore_errors=True) else: - item.unlink() + item.unlink(missing_ok=True) def get_env(self) -> dict: """Return environment variables configured for isolated testing.""" diff --git a/python/pyproject.toml b/python/pyproject.toml index d5177af3..b902b050 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -42,6 +42,7 @@ dev = [ "ty>=0.0.2", "pytest>=7.0.0", "pytest-asyncio>=0.21.0", + "pytest-timeout>=2.0.0", "httpx>=0.24.0", ] diff --git a/python/uv.lock b/python/uv.lock index 8208e384..35134a0b 100644 --- a/python/uv.lock +++ b/python/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 3 +revision = 2 requires-python = ">=3.9" resolution-markers = [ "python_full_version >= '3.10'", @@ -85,6 +85,7 @@ dev = [ { name = "pytest", version = "9.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "pytest-asyncio", version = "1.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "pytest-asyncio", version = "1.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pytest-timeout" }, { name = "ruff" }, { name = "ty" }, ] @@ -95,6 +96,7 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.0" }, { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.0.0" }, { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.21.0" }, + { name = "pytest-timeout", marker = "extra == 'dev'", specifier = ">=2.0.0" }, { name = "python-dateutil", specifier = ">=2.9.0.post0" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.1.0" }, { name = "ty", marker = "extra == 'dev'", specifier = ">=0.0.2" }, @@ -421,6 +423,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45.537Z" }, ] +[[package]] +name = "pytest-timeout" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "pytest", version = "9.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/82/4c9ecabab13363e72d880f2fb504c5f750433b2b6f16e99f4ec21ada284c/pytest_timeout-2.4.0.tar.gz", hash = "sha256:7e68e90b01f9eff71332b25001f85c75495fc4e3a836701876183c4bcfd0540a", size = 17973, upload-time = "2025-05-05T19:44:34.99Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/b6/3127540ecdf1464a00e5a01ee60a1b09175f6913f0644ac748494d9c4b21/pytest_timeout-2.4.0-py3-none-any.whl", hash = "sha256:c42667e5cdadb151aeb5b26d114aff6bdf5a907f176a007a30b940d3d865b5c2", size = 14382, upload-time = "2025-05-05T19:44:33.502Z" }, +] + [[package]] name = "python-dateutil" version = "2.9.0.post0"