diff --git a/.all-contributorsrc b/.all-contributorsrc
index ddbacfcd34..e0ca6b8c09 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -1688,6 +1688,15 @@
"contributions": [
"bug"
]
+ },
+ {
+ "login": "sherbang",
+ "name": "sherbang",
+ "avatar_url": "https://avatars.githubusercontent.com/u/275015?v=4",
+ "profile": "https://github.com/sherbang",
+ "contributions": [
+ "doc"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index bbf0986b56..766279dcb1 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -81,6 +81,31 @@ jobs:
- name: Run pyright
run: pdm run pyright
+ slotscheck:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-python@v5
+ with:
+ python-version: "3.8"
+ allow-prereleases: false
+
+ - uses: pdm-project/setup-pdm@v4
+ name: Set up PDM
+ with:
+ python-version: "3.8"
+ allow-python-prereleases: false
+ cache: true
+ cache-dependency-path: |
+ ./pdm.lock
+
+ - name: Install dependencies
+ run: pdm install -G:all
+
+ - name: Run slotscheck
+ run: pdm run slotscheck litestar
+
test:
name: "test (${{ matrix.python-version }})"
strategy:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index abdb4aac6d..ecf00f31c9 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -41,11 +41,6 @@ repos:
- id: ensure-dunder-all
exclude: "test*|examples*|tools"
args: ["--use-tuple"]
- - repo: https://github.com/ariebovenberg/slotscheck
- rev: v0.19.0
- hooks:
- - id: slotscheck
- exclude: "test_*|docs|.github"
- repo: https://github.com/sphinx-contrib/sphinx-lint
rev: "v0.9.1"
hooks:
diff --git a/Makefile b/Makefile
index 4407d391da..b17df23549 100644
--- a/Makefile
+++ b/Makefile
@@ -102,8 +102,14 @@ pre-commit: ## Runs pre-commit hooks; includes ruff formatting and lin
@$(PDM) run pre-commit run --all-files
@echo "=> Pre-commit complete"
+.PHONY: slots-check
+slots-check: ## Check for slots usage in classes
+ @echo "=> Checking for slots usage in classes"
+ @$(PDM) run slotscheck litestar
+ @echo "=> Slots check complete"
+
.PHONY: lint
-lint: pre-commit type-check ## Run all linting
+lint: pre-commit type-check slots-check ## Run all linting
.PHONY: coverage
coverage: ## Run the tests and generate coverage report
diff --git a/README.md b/README.md
index fc277654d9..2469b993e5 100644
--- a/README.md
+++ b/README.md
@@ -129,10 +129,10 @@ A **huge** thanks to our sponsors:
Check out our sponsors in the docs
-If you would like to support the work that we do please consider [becoming a sponsor][sponsor-github]
-on [GitHub][sponsor-github] or [Open Collective][sponsor-oc].
+If you would like to support the work that we do please consider [becoming a sponsor][sponsor-polar]
+via [Polar.sh][sponsor-polar] (preferred), [GitHub][sponsor-github] or [Open Collective][sponsor-oc].
-We also participate in pledge-based sponsorship with [Polar][sponsor-polar].
+Also, exclusively with [Polar][sponsor-polar], you can engage in pledge-based sponsorships.
[sponsor-github]: https://github.com/sponsors/litestar-org
[sponsor-oc]: https://opencollective.com/litestar
@@ -554,6 +554,7 @@ see [the contribution guide](CONTRIBUTING.rst).
James Bennett 🐛 |
+ sherbang 📖 |
diff --git a/docs/PYPI_README.md b/docs/PYPI_README.md
index 4ee50f7aca..ddef0ed1ed 100644
--- a/docs/PYPI_README.md
+++ b/docs/PYPI_README.md
@@ -126,10 +126,10 @@ A **huge** thanks to our sponsors:
Check out our sponsors in the docs
-If you would like to support the work that we do please consider [becoming a sponsor][sponsor-github]
-on [GitHub][sponsor-github] or [Open Collective][sponsor-oc].
+If you would like to support the work that we do please consider [becoming a sponsor][sponsor-polar]
+via [Polar.sh][sponsor-polar] (preferred), [GitHub][sponsor-github] or [Open Collective][sponsor-oc].
-We also participate in pledge-based sponsorship with [Polar][sponsor-polar].
+Also, exclusively with [Polar][sponsor-polar], you can engage in pledge-based sponsorships.
[sponsor-github]: https://github.com/sponsors/litestar-org
[sponsor-oc]: https://opencollective.com/litestar
diff --git a/docs/index.rst b/docs/index.rst
index f526e32898..3fb006fa79 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -164,11 +164,10 @@ A huge thank you to our current sponsors:
We invite organizations and individuals to join our sponsorship program.
-By becoming a sponsor on platforms like `GitHub `_
+By becoming a sponsor on `Polar `_ (preferred), or other platforms like `GitHub `_
and `Open Collective `_, you can play a pivotal role in our project's growth.
-Additionally, we engage in pledge-based sponsorship opportunities through `Polar `_.
-
+Also, exclusively with `Polar `_, you can engage in pledge-based sponsorships.
.. _sponsor-github: https://github.com/sponsors/litestar-org
.. _sponsor-oc: https://opencollective.com/litestar
diff --git a/docs/release-notes/changelog.rst b/docs/release-notes/changelog.rst
index 75caa3a854..5bbc846f09 100644
--- a/docs/release-notes/changelog.rst
+++ b/docs/release-notes/changelog.rst
@@ -6,12 +6,6 @@
.. changelog:: 2.7.1
:date: 2024-03-22
- .. change:: add default encoders for `Enums` and `EnumMeta`
- :type: bugfix
- :pr: 3193
-
- This addresses an issue when serializing ``Enums`` that was reported in discord.
-
.. change:: replace TestClient.__enter__ return type with Self
:type: bugfix
:pr: 3194
diff --git a/litestar/app.py b/litestar/app.py
index eaa796c468..3dbdbf676f 100644
--- a/litestar/app.py
+++ b/litestar/app.py
@@ -151,21 +151,17 @@ class Litestar(Router):
"csrf_config",
"event_emitter",
"get_logger",
- "include_in_schema",
"logger",
"logging_config",
"multipart_form_part_limit",
"on_shutdown",
"on_startup",
"openapi_config",
- "request_class",
"response_cache_config",
"route_map",
- "signature_namespace",
"state",
"stores",
"template_engine",
- "websocket_class",
"pdb_on_exception",
"experimental_features",
)
diff --git a/litestar/cli/__init__.py b/litestar/cli/__init__.py
index f6c366e495..7dabefaae9 100644
--- a/litestar/cli/__init__.py
+++ b/litestar/cli/__init__.py
@@ -14,8 +14,6 @@
click.rich_click.USE_MARKDOWN = False
click.rich_click.SHOW_ARGUMENTS = True
click.rich_click.GROUP_ARGUMENTS_OPTIONS = True
- click.rich_click.SHOW_ARGUMENTS = True
- click.rich_click.GROUP_ARGUMENTS_OPTIONS = True
click.rich_click.STYLE_ERRORS_SUGGESTION = "magenta italic"
click.rich_click.ERRORS_SUGGESTION = ""
click.rich_click.ERRORS_EPILOGUE = ""
diff --git a/litestar/contrib/opentelemetry/middleware.py b/litestar/contrib/opentelemetry/middleware.py
index 762bae9125..59ea4dce06 100644
--- a/litestar/contrib/opentelemetry/middleware.py
+++ b/litestar/contrib/opentelemetry/middleware.py
@@ -24,8 +24,6 @@
class OpenTelemetryInstrumentationMiddleware(AbstractMiddleware):
"""OpenTelemetry Middleware."""
- __slots__ = ("open_telemetry_middleware",)
-
def __init__(self, app: ASGIApp, config: OpenTelemetryConfig) -> None:
"""Middleware that adds OpenTelemetry instrumentation to the application.
diff --git a/litestar/dto/_types.py b/litestar/dto/_types.py
index 24e99b793b..b0863b2593 100644
--- a/litestar/dto/_types.py
+++ b/litestar/dto/_types.py
@@ -96,9 +96,6 @@ class MappingType(CompositeType):
@dataclass(frozen=True)
class TransferDTOFieldDefinition(DTOFieldDefinition):
__slots__ = (
- "default_factory",
- "dto_field",
- "model_name",
"is_excluded",
"is_partial",
"serialization_name",
diff --git a/litestar/handlers/websocket_handlers/listener.py b/litestar/handlers/websocket_handlers/listener.py
index 86fefc913a..8e702ea1aa 100644
--- a/litestar/handlers/websocket_handlers/listener.py
+++ b/litestar/handlers/websocket_handlers/listener.py
@@ -62,11 +62,10 @@ class WebsocketListenerRouteHandler(WebsocketRouteHandler):
"connection_accept_handler": "Callback to accept a WebSocket connection. By default, calls WebSocket.accept",
"on_accept": "Callback invoked after a WebSocket connection has been accepted",
"on_disconnect": "Callback invoked after a WebSocket connection has been closed",
- "weboscket_class": "WebSocket class",
"_connection_lifespan": None,
- "_handle_receive": None,
- "_handle_send": None,
+ "_receive_handler": None,
"_receive_mode": None,
+ "_send_handler": None,
"_send_mode": None,
}
diff --git a/litestar/handlers/websocket_handlers/route_handler.py b/litestar/handlers/websocket_handlers/route_handler.py
index edb49c3030..4b8953ee26 100644
--- a/litestar/handlers/websocket_handlers/route_handler.py
+++ b/litestar/handlers/websocket_handlers/route_handler.py
@@ -18,6 +18,8 @@ class WebsocketRouteHandler(BaseRouteHandler):
Use this decorator to decorate websocket handler functions.
"""
+ __slots__ = ("websocket_class",)
+
def __init__(
self,
path: str | list[str] | None = None,
diff --git a/litestar/middleware/compression/facade.py b/litestar/middleware/compression/facade.py
index 0074b57419..a1a62728ce 100644
--- a/litestar/middleware/compression/facade.py
+++ b/litestar/middleware/compression/facade.py
@@ -12,6 +12,8 @@
class CompressionFacade(Protocol):
"""A unified facade offering a uniform interface for different compression libraries."""
+ __slots__ = ()
+
encoding: ClassVar[str]
"""The encoding of the compression."""
diff --git a/litestar/middleware/cors.py b/litestar/middleware/cors.py
index 6c4de31f8f..010576aa6a 100644
--- a/litestar/middleware/cors.py
+++ b/litestar/middleware/cors.py
@@ -17,8 +17,6 @@
class CORSMiddleware(AbstractMiddleware):
"""CORS Middleware."""
- __slots__ = ("config",)
-
def __init__(self, app: ASGIApp, config: CORSConfig) -> None:
"""Middleware that adds CORS validation to the application.
diff --git a/litestar/middleware/logging.py b/litestar/middleware/logging.py
index 0094f10cfa..c986eb6433 100644
--- a/litestar/middleware/logging.py
+++ b/litestar/middleware/logging.py
@@ -48,8 +48,6 @@
class LoggingMiddleware(AbstractMiddleware):
"""Logging middleware."""
- __slots__ = ("config", "logger", "request_extractor", "response_extractor", "is_struct_logger")
-
logger: Logger
def __init__(self, app: ASGIApp, config: LoggingMiddlewareConfig) -> None:
diff --git a/litestar/middleware/rate_limit.py b/litestar/middleware/rate_limit.py
index cd767ba4a2..0c3de7f6e5 100644
--- a/litestar/middleware/rate_limit.py
+++ b/litestar/middleware/rate_limit.py
@@ -41,8 +41,6 @@ class CacheObject:
class RateLimitMiddleware(AbstractMiddleware):
"""Rate-limiting middleware."""
- __slots__ = ("app", "check_throttle_handler", "max_requests", "unit", "request_quota", "config")
-
def __init__(self, app: ASGIApp, config: RateLimitConfig) -> None:
"""Initialize ``RateLimitMiddleware``.
diff --git a/litestar/plugins/base.py b/litestar/plugins/base.py
index afc571efe7..65710c9fc0 100644
--- a/litestar/plugins/base.py
+++ b/litestar/plugins/base.py
@@ -212,6 +212,8 @@ def to_openapi_schema(self, field_definition: FieldDefinition, schema_creator: S
class OpenAPISchemaPlugin(OpenAPISchemaPluginProtocol):
"""Plugin to extend the support of OpenAPI schema generation for non-library types."""
+ __slots__ = ()
+
@staticmethod
def is_plugin_supported_type(value: Any) -> bool:
"""Given a value of indeterminate type, determine if this value is supported by the plugin.
diff --git a/litestar/stores/base.py b/litestar/stores/base.py
index 34aa514fca..69a63663e5 100644
--- a/litestar/stores/base.py
+++ b/litestar/stores/base.py
@@ -20,6 +20,8 @@
class Store(ABC):
"""Thread and process safe asynchronous key/value store."""
+ __slots__ = ()
+
@abstractmethod
async def set(self, key: str, value: str | bytes, expires_in: int | timedelta | None = None) -> None:
"""Set a value.
@@ -97,6 +99,8 @@ class NamespacedStore(Store):
should be isolated.
"""
+ __slots__ = ("namespace",)
+
@abstractmethod
def with_namespace(self, namespace: str) -> Self:
"""Return a new instance of :class:`NamespacedStore`, which exists in a child namespace of the current namespace.
diff --git a/litestar/stores/redis.py b/litestar/stores/redis.py
index 6697962fab..4b46097199 100644
--- a/litestar/stores/redis.py
+++ b/litestar/stores/redis.py
@@ -21,7 +21,12 @@
class RedisStore(NamespacedStore):
"""Redis based, thread and process safe asynchronous key/value store."""
- __slots__ = ("_redis",)
+ __slots__ = (
+ "_delete_all_script",
+ "_get_and_renew_script",
+ "_redis",
+ "handle_client_shutdown",
+ )
def __init__(
self, redis: Redis, namespace: str | None | EmptyType = Empty, handle_client_shutdown: bool = False
diff --git a/litestar/typing.py b/litestar/typing.py
index 3a275573f3..14a92dc44f 100644
--- a/litestar/typing.py
+++ b/litestar/typing.py
@@ -96,7 +96,7 @@ def _parse_metadata(value: Any, is_sequence_container: bool, extra: dict[str, An
example_list: list[Any] | None
if example := extra.pop("example", None):
example_list = [Example(value=example)]
- elif examples := getattr(value, "examples", None):
+ elif examples := (extra.pop("examples", None) or getattr(value, "examples", None)):
example_list = [Example(value=example) for example in cast("list[str]", examples)]
else:
example_list = None
diff --git a/pyproject.toml b/pyproject.toml
index 1dfc87b68b..3eb1d2489d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -285,6 +285,12 @@ reportUnnecessaryTypeIgnoreComments = true
[tool.slotscheck]
strict-imports = false
+exclude-classes = """
+(
+ # github.com/python/cpython/pull/106771
+ (^litestar.events.emitter:BaseEventEmitterBackend)
+)
+"""
[tool.ruff]
lint.select = [
diff --git a/tests/unit/test_contrib/test_pydantic/test_openapi.py b/tests/unit/test_contrib/test_pydantic/test_openapi.py
index aa84def09b..4407b79980 100644
--- a/tests/unit/test_contrib/test_pydantic/test_openapi.py
+++ b/tests/unit/test_contrib/test_pydantic/test_openapi.py
@@ -553,6 +553,26 @@ class Model(pydantic_v2.BaseModel):
assert value.examples == ["example"]
+def test_create_schema_for_field_v2__examples() -> None:
+ class Model(pydantic_v2.BaseModel):
+ value: str = pydantic_v2.Field(
+ title="title", description="description", max_length=16, json_schema_extra={"examples": ["example"]}
+ )
+
+ schema = get_schema_for_field_definition(
+ FieldDefinition.from_kwarg(name="Model", annotation=Model), plugins=[PydanticSchemaPlugin()]
+ )
+
+ assert schema.properties
+
+ value = schema.properties["value"]
+
+ assert isinstance(value, Schema)
+ assert value.description == "description"
+ assert value.title == "title"
+ assert value.examples == ["example"]
+
+
@pytest.mark.parametrize("with_future_annotations", [True, False])
def test_create_schema_for_pydantic_model_with_annotated_model_attribute(
with_future_annotations: bool, create_module: "Callable[[str], ModuleType]", pydantic_version: PydanticVersion