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/application_hooks/before_send_hook.py b/docs/examples/application_hooks/before_send_hook.py
--- a/docs/examples/application_hooks/before_send_hook.py
+++ b/docs/examples/application_hooks/before_send_hook.py
@@ -1,11 +1,15 @@
-from typing import TYPE_CHECKING, Dict
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
 
 from starlite import Starlite, get
 from starlite.datastructures import MutableScopeHeaders
 
 if TYPE_CHECKING:
+    from typing import Dict
+
     from starlite.datastructures import State
-    from starlite.types import Message
+    from starlite.types import Message, Scope
 
 
 @get("/test")
@@ -14,7 +18,7 @@ def handler() -> Dict[str, str]:
     return {"key": "value"}
 
 
-async def before_send_hook_handler(message: "Message", state: "State") -> None:
+async def before_send_hook_handler(message: Message, state: State, scope: Scope) -> None:
     """The function will be called on each ASGI message.
 
     We therefore ensure it runs only on the message start event.
@@ -24,7 +28,7 @@ async def before_send_hook_handler(message: "Message", state: "State") -> None:
         headers["My Header"] = state.message
 
 
-def on_startup(state: "State") -> None:
+def on_startup(state: State) -> None:
     """A function that will populate the app state before any requests are received."""
     state.message = "value injected during send"
 
diff --git a/starlite/app.py b/starlite/app.py
--- a/starlite/app.py
+++ b/starlite/app.py
@@ -738,10 +738,7 @@ def _wrap_send(self, send: Send, scope: Scope) -> Send:
 
             async def wrapped_send(message: "Message") -> None:
                 for hook in self.before_send:
-                    if hook.num_expected_args > 2:
-                        await hook(message, self.state, scope)
-                    else:
-                        await hook(message, self.state)
+                    await hook(message, self.state, scope)
                 await send(message)
 
             return wrapped_send
diff --git a/starlite/types/callable_types.py b/starlite/types/callable_types.py
--- a/starlite/types/callable_types.py
+++ b/starlite/types/callable_types.py
@@ -42,9 +42,7 @@
 AsyncAnyCallable = Callable[..., Awaitable[Any]]
 AnyCallable = Callable[..., Any]
 AnyGenerator = Union[Generator[Any, Any, Any], AsyncGenerator[Any, Any]]
-BeforeMessageSendHookHandler = Union[
-    Callable[[Message, State, Scope], SyncOrAsyncUnion[None]], Callable[[Message, State], SyncOrAsyncUnion[None]]
-]
+BeforeMessageSendHookHandler = Callable[[Message, State, Scope], SyncOrAsyncUnion[None]]
 BeforeRequestHookHandler = Callable[[Request], Union[Any, Awaitable[Any]]]
 CacheKeyBuilder = Callable[[Request], str]
 ExceptionHandler = Callable[[Request, ExceptionT], Response]


Test patch:
diff --git a/tests/app/test_before_send.py b/tests/app/test_before_send.py
--- a/tests/app/test_before_send.py
+++ b/tests/app/test_before_send.py
@@ -1,4 +1,7 @@
-from typing import TYPE_CHECKING, Dict
+# ruff: noqa: UP006
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
 
 from starlite import get
 from starlite.datastructures import MutableScopeHeaders
@@ -6,8 +9,10 @@
 from starlite.testing import create_test_client
 
 if TYPE_CHECKING:
+    from typing import Dict
+
     from starlite.datastructures import State
-    from starlite.types import Message
+    from starlite.types import Message, Scope
 
 
 def test_before_send() -> None:
@@ -15,7 +20,7 @@ def test_before_send() -> None:
     def handler() -> Dict[str, str]:
         return {"key": "value"}
 
-    async def before_send_hook_handler(message: "Message", state: "State") -> None:
+    async def before_send_hook_handler(message: Message, state: State, scope: Scope) -> None:
         if message["type"] == "http.response.start":
             headers = MutableScopeHeaders(message)
             headers.add("My Header", state.message)