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/litestar/contrib/sqlalchemy/base.py b/litestar/contrib/sqlalchemy/base.py
--- a/litestar/contrib/sqlalchemy/base.py
+++ b/litestar/contrib/sqlalchemy/base.py
@@ -137,7 +137,7 @@ def to_dict(self, exclude: set[str] | None = None) -> dict[str, Any]:
         Returns:
             dict[str, Any]: A dict representation of the model
         """
-        exclude = exclude.union("_sentinel") if exclude else {"_sentinel"}
+        exclude = {"_sentinel"}.union(self._sa_instance_state.unloaded).union(exclude or [])  # type: ignore[attr-defined]
         return {field.name: getattr(self, field.name) for field in self.__table__.columns if field.name not in exclude}
 
 


Test patch:
diff --git a/tests/contrib/sqlalchemy/repository/test_sqlalchemy_async.py b/tests/contrib/sqlalchemy/repository/test_sqlalchemy_async.py
--- a/tests/contrib/sqlalchemy/repository/test_sqlalchemy_async.py
+++ b/tests/contrib/sqlalchemy/repository/test_sqlalchemy_async.py
@@ -7,11 +7,12 @@
 from uuid import uuid4
 
 import pytest
+from sqlalchemy import String
 from sqlalchemy.exc import IntegrityError, InvalidRequestError, SQLAlchemyError
 from sqlalchemy.ext.asyncio import (
     AsyncSession,
 )
-from sqlalchemy.orm import MappedColumn
+from sqlalchemy.orm import Mapped, MappedColumn, mapped_column
 
 from litestar.contrib.repository.exceptions import ConflictError, RepositoryError
 from litestar.contrib.repository.filters import (
@@ -74,26 +75,35 @@ class AnotherModel(base.UUIDAuditBase):
         """Inheriting from UUIDAuditBase gives the model 'created' and 'updated'
         columns."""
 
-        ...
+        the_extra_col: Mapped[str] = mapped_column(String(length=100), nullable=True)  # pyright: ignore
 
     class TheTestModel(base.UUIDBase):
         """Inheriting from DeclarativeBase gives the model 'id'  columns."""
 
-        ...
+        the_extra_col: Mapped[str] = mapped_column(String(length=100), nullable=True)  # pyright: ignore
 
     class TheBigIntModel(base.BigIntBase):
         """Inheriting from DeclarativeBase gives the model 'id'  columns."""
 
-        ...
+        the_extra_col: Mapped[str] = mapped_column(String(length=100), nullable=True)  # pyright: ignore
+
+    unloaded_cols = {"the_extra_col"}
+    sa_instance_mock = MagicMock()
+    sa_instance_mock.unloaded = unloaded_cols
 
     assert isinstance(AnotherModel._sentinel, MappedColumn)
     assert isinstance(TheTestModel._sentinel, MappedColumn)
     assert not hasattr(TheBigIntModel, "_sentinel")
     model1, model2, model3 = AnotherModel(), TheTestModel(), TheBigIntModel()
+    monkeypatch.setattr(model1, "_sa_instance_state", sa_instance_mock)
+    monkeypatch.setattr(model2, "_sa_instance_state", sa_instance_mock)
+    monkeypatch.setattr(model3, "_sa_instance_state", sa_instance_mock)
     assert "created" not in model1.to_dict(exclude={"created"}).keys()
+    assert "the_extra_col" not in model1.to_dict(exclude={"created"}).keys()
     assert "_sentinel" not in model1.to_dict().keys()
     assert "_sentinel" not in model2.to_dict().keys()
     assert "_sentinel" not in model3.to_dict().keys()
+    assert "the_extra_col" not in model1.to_dict().keys()
 
 
 def test_wrap_sqlalchemy_integrity_error() -> None:
diff --git a/tests/contrib/sqlalchemy/repository/test_sqlalchemy_sync.py b/tests/contrib/sqlalchemy/repository/test_sqlalchemy_sync.py
--- a/tests/contrib/sqlalchemy/repository/test_sqlalchemy_sync.py
+++ b/tests/contrib/sqlalchemy/repository/test_sqlalchemy_sync.py
@@ -7,8 +7,9 @@
 from uuid import uuid4
 
 import pytest
+from sqlalchemy import String
 from sqlalchemy.exc import IntegrityError, InvalidRequestError, SQLAlchemyError
-from sqlalchemy.orm import MappedColumn, Session
+from sqlalchemy.orm import Mapped, MappedColumn, Session, mapped_column
 
 from litestar.contrib.repository.exceptions import ConflictError, RepositoryError
 from litestar.contrib.repository.filters import (
@@ -71,26 +72,34 @@ class AnotherModel(base.UUIDAuditBase):
         """Inheriting from UUIDAuditBase gives the model 'created' and 'updated'
         columns."""
 
-        ...
+        the_extra_col: Mapped[str] = mapped_column(String(length=100), nullable=True)  # pyright: ignore
 
     class TheTestModel(base.UUIDBase):
         """Inheriting from DeclarativeBase gives the model 'id'  columns."""
 
-        ...
+        the_extra_col: Mapped[str] = mapped_column(String(length=100), nullable=True)  # pyright: ignore
 
     class TheBigIntModel(base.BigIntBase):
         """Inheriting from DeclarativeBase gives the model 'id'  columns."""
 
-        ...
+        the_extra_col: Mapped[str] = mapped_column(String(length=100), nullable=True)  # pyright: ignore
 
+    unloaded_cols = {"the_extra_col"}
+    sa_instance_mock = MagicMock()
+    sa_instance_mock.unloaded = unloaded_cols
     assert isinstance(AnotherModel._sentinel, MappedColumn)
     assert isinstance(TheTestModel._sentinel, MappedColumn)
     assert not hasattr(TheBigIntModel, "_sentinel")
     model1, model2, model3 = AnotherModel(), TheTestModel(), TheBigIntModel()
+    monkeypatch.setattr(model1, "_sa_instance_state", sa_instance_mock)
+    monkeypatch.setattr(model2, "_sa_instance_state", sa_instance_mock)
+    monkeypatch.setattr(model3, "_sa_instance_state", sa_instance_mock)
     assert "created" not in model1.to_dict(exclude={"created"}).keys()
+    assert "the_extra_col" not in model1.to_dict(exclude={"created"}).keys()
     assert "_sentinel" not in model1.to_dict().keys()
     assert "_sentinel" not in model2.to_dict().keys()
     assert "_sentinel" not in model3.to_dict().keys()
+    assert "the_extra_col" not in model1.to_dict().keys()
 
 
 def test_wrap_sqlalchemy_integrity_error() -> None: