Repository: litestar-org/litestar

Issue:
StaticFilesConfig and virtual directories
I'm trying to write a ``FileSystemProtocol`` to load files from the package data using [importlib_resources](https://importlib-resources.readthedocs.io/en/latest/using.html#). But because ``directories`` is defined as ``DirectoryPath``, pydantic checks if the given directories exist in the local filesystem. 

This is not generally true, especially in any kind of virtual filesystem (e.g. a zipped package). I think this condition should be relaxed to support virtual filesystems.

https://github.com/starlite-api/starlite/blob/9bb6dcd57c10a591377cf8e3a537e9292566d5b9/starlite/config/static_files.py#L32


Discussion:
I agree. Do you want to submit a PR?

Resolving patch:
diff --git a/docs/examples/conftest.py b/docs/examples/conftest.py
new file mode 100644
--- /dev/null
+++ b/docs/examples/conftest.py
@@ -0,0 +1 @@
+from tests.conftest import reset_httpx_logging  # noqa: F401


Test patch:
diff --git a/docs/examples/tests/application_hooks/test_application_after_exception_hook.py b/docs/examples/tests/application_hooks/test_application_after_exception_hook.py
--- a/docs/examples/tests/application_hooks/test_application_after_exception_hook.py
+++ b/docs/examples/tests/application_hooks/test_application_after_exception_hook.py
@@ -1,6 +1,8 @@
 import logging
 from typing import TYPE_CHECKING
 
+import pytest
+
 from examples.application_hooks import after_exception_hook
 from litestar.testing import TestClient
 
@@ -8,6 +10,7 @@
     from _pytest.logging import LogCaptureFixture
 
 
+@pytest.mark.usefixtures("reset_httpx_logging")
 def test_application_shutdown_hooks(caplog: "LogCaptureFixture") -> None:
     with caplog.at_level(logging.INFO), TestClient(app=after_exception_hook.app) as client:
         assert len(caplog.messages) == 0
diff --git a/docs/examples/tests/application_state/test_using_application_state.py b/docs/examples/tests/application_state/test_using_application_state.py
--- a/docs/examples/tests/application_state/test_using_application_state.py
+++ b/docs/examples/tests/application_state/test_using_application_state.py
@@ -1,11 +1,14 @@
 from logging import INFO
 from typing import Any
 
+import pytest
+
 from examples.application_state.using_application_state import app
 from litestar.status_codes import HTTP_200_OK
 from litestar.testing import TestClient
 
 
+@pytest.mark.usefixtures("reset_httpx_logging")
 def test_using_application_state(caplog: Any) -> None:
     with caplog.at_level(INFO, "examples.application_state.using_application_state"), TestClient(app=app) as client:
         response = client.get("/")
diff --git a/docs/examples/tests/middleware/test_logging_middleware.py b/docs/examples/tests/middleware/test_logging_middleware.py
--- a/docs/examples/tests/middleware/test_logging_middleware.py
+++ b/docs/examples/tests/middleware/test_logging_middleware.py
@@ -25,6 +25,7 @@ def get_logger() -> "GetLogger":
     ).configure()
 
 
+@pytest.mark.usefixtures("reset_httpx_logging")
 def test_logging_middleware_regular_logger(get_logger: "GetLogger", caplog: "LogCaptureFixture") -> None:
     with TestClient(app=app) as client, caplog.at_level(logging.INFO):
         client.app.get_logger = get_logger
diff --git a/docs/examples/tests/responses/test_background_tasks.py b/docs/examples/tests/responses/test_background_tasks.py
--- a/docs/examples/tests/responses/test_background_tasks.py
+++ b/docs/examples/tests/responses/test_background_tasks.py
@@ -1,6 +1,8 @@
 import logging
 from typing import TYPE_CHECKING
 
+import pytest
+
 from examples.responses.background_tasks_1 import app as app_1
 from examples.responses.background_tasks_2 import app as app_2
 from examples.responses.background_tasks_3 import app as app_3
@@ -11,6 +13,9 @@
     from _pytest.logging import LogCaptureFixture
 
 
+pytestmark = pytest.mark.usefixtures("reset_httpx_logging")
+
+
 def test_background_tasks_1(caplog: "LogCaptureFixture") -> None:
     with caplog.at_level(logging.INFO), TestClient(app=app_1) as client:
         name = "Jane"
diff --git a/litestar/testing/client/async_client.py b/litestar/testing/client/async_client.py
--- a/litestar/testing/client/async_client.py
+++ b/litestar/testing/client/async_client.py
@@ -1,6 +1,5 @@
 from __future__ import annotations
 
-import logging
 from contextlib import AsyncExitStack
 from typing import TYPE_CHECKING, Any, Generic, Mapping, TypeVar
 
@@ -31,9 +30,6 @@
 
 T = TypeVar("T", bound=ASGIApp)
 
-# ensure that httpx logging is not interfering with our test client
-logging.getLogger("httpx").setLevel(logging.WARNING)
-
 
 class AsyncTestClient(AsyncClient, BaseTestClient, Generic[T]):  # type: ignore[misc]
     lifespan_handler: LifeSpanHandler
diff --git a/litestar/testing/client/sync_client.py b/litestar/testing/client/sync_client.py
--- a/litestar/testing/client/sync_client.py
+++ b/litestar/testing/client/sync_client.py
@@ -1,6 +1,5 @@
 from __future__ import annotations
 
-import logging
 from contextlib import ExitStack
 from typing import TYPE_CHECKING, Any, Generic, Mapping, TypeVar
 from urllib.parse import urljoin
@@ -34,9 +33,6 @@
 
 T = TypeVar("T", bound=ASGIApp)
 
-# ensure that httpx logging is not interfering with our test client
-logging.getLogger("httpx").setLevel(logging.WARNING)
-
 
 class TestClient(Client, BaseTestClient, Generic[T]):  # type: ignore[misc]
     lifespan_handler: LifeSpanHandler
diff --git a/tests/conftest.py b/tests/conftest.py
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,4 +1,5 @@
 import importlib.util
+import logging
 import sys
 from os import environ, urandom
 from pathlib import Path
@@ -285,3 +286,13 @@ def mock_db() -> MemoryStore:
 def frozen_datetime() -> Generator["FrozenDateTimeFactory", None, None]:
     with freeze_time() as frozen:
         yield cast("FrozenDateTimeFactory", frozen)
+
+
+@pytest.fixture()
+def reset_httpx_logging() -> Generator[None, None, None]:
+    # ensure that httpx logging is not interfering with our test client
+    httpx_logger = logging.getLogger("httpx")
+    initial_level = httpx_logger.level
+    httpx_logger.setLevel(logging.WARNING)
+    yield
+    httpx_logger.setLevel(initial_level)
diff --git a/tests/middleware/test_logging_middleware.py b/tests/middleware/test_logging_middleware.py
--- a/tests/middleware/test_logging_middleware.py
+++ b/tests/middleware/test_logging_middleware.py
@@ -21,6 +21,9 @@
     from litestar.types.callable_types import GetLogger
 
 
+pytestmark = pytest.mark.usefixtures("reset_httpx_logging")
+
+
 @get("/")
 def handler() -> Response:
     return Response(