From 36ce1c9fb94afa045471c9a3ddb784e54a259d4c Mon Sep 17 00:00:00 2001 From: Cody Fincher Date: Thu, 10 Sep 2026 18:56:41 +0000 Subject: [PATCH 1/2] fix: unify public Litestar configuration type --- sqlspec/extensions/litestar/config.py | 97 +------------------ tests/typing/typing_litestar_config.py | 24 +++++ .../test_litestar/test_config_typing.py | 10 ++ 3 files changed, 36 insertions(+), 95 deletions(-) create mode 100644 tests/typing/typing_litestar_config.py create mode 100644 tests/unit/extensions/test_litestar/test_config_typing.py diff --git a/sqlspec/extensions/litestar/config.py b/sqlspec/extensions/litestar/config.py index cf8dc5efc..87a6ef1a1 100644 --- a/sqlspec/extensions/litestar/config.py +++ b/sqlspec/extensions/litestar/config.py @@ -1,98 +1,5 @@ -"""Configuration types for Litestar session store extension.""" +"""Configuration types for the Litestar SQLSpec extension.""" -from typing import Any, Literal - -from typing_extensions import NotRequired, TypedDict +from sqlspec.config import LitestarConfig __all__ = ("LitestarConfig",) - - -class LitestarConfig(TypedDict): - """Configuration options for Litestar session store extension. - - All fields are optional with sensible defaults. Use in extension_config["litestar"]: - """ - - manage_schema: NotRequired[bool] - """Apply additive target-schema reconciliation. Default: True.""" - - create_schema: NotRequired[bool] - """Create the session table during managed reconciliation. Default: True.""" - - run_migrations: NotRequired[bool] - """Run packaged versioned migrations when an integration supplies a runner. Default: False.""" - - session_table: NotRequired[str] - """Name of the sessions table. Default: 'litestar_session'""" - - in_memory: NotRequired[bool] - """ - Enable in-memory table storage (Oracle-specific). Default: False. - - When enabled, tables are created with the in-memory attribute for databases that support it. - - This is an Oracle-specific feature that requires: - - Oracle Database 12.1.0.2 or higher - - Database In-Memory option license (Enterprise Edition) - - Sufficient INMEMORY_SIZE configured in the database instance - - Other database adapters ignore this setting. - """ - - shard_count: NotRequired[int] - """ - Optional hash shard count for session table primary key. - - When set (>1), adapters that support computed shard columns - will create a generated shard_id using MOD(FARM_FINGERPRINT(session_id), shard_count) - and include it in the primary key to reduce hotspotting. Ignored by adapters - that do not support computed shards. - """ - - table_options: NotRequired[str] - """ - Optional raw OPTIONS/engine-specific table options string. - - Passed verbatim when the adapter supports table-level OPTIONS/clauses. Ignored by adapters that do not - support table options. - """ - - index_options: NotRequired[str] - """Optional raw OPTIONS/engine-specific options for the expires_at index. - - Passed verbatim to the index definition for adapters that support index - OPTIONS/clauses. Ignored by adapters that do not support index options. - """ - - partitioning: NotRequired[dict[str, Any]] - """Configure adapter-specific session-table partitioning where supported.""" - - partition_expiration_days: NotRequired[int] - """Set BigQuery partition expiration in days.""" - - require_partition_filter: NotRequired[bool] - """Require partition filters for BigQuery session queries.""" - - enable_hash_sharded_indexes: NotRequired[bool] - """Enable CockroachDB hash-sharded session indexes.""" - - hash_shard_bucket_count: NotRequired[int] - """Set the CockroachDB hash-shard bucket count.""" - - ttl_expiration_expression: NotRequired[Literal[False, "expires_at"]] - """Enable CockroachDB row-level TTL using the session ``expires_at`` column.""" - - fillfactor: NotRequired[int] - """Set PostgreSQL-family session-table fillfactor. Default: 80.""" - - autovacuum_vacuum_scale_factor: NotRequired[float] - """Set the PostgreSQL-family autovacuum vacuum scale factor.""" - - autovacuum_analyze_scale_factor: NotRequired[float] - """Set the PostgreSQL-family autovacuum analyze scale factor.""" - - pragma_profile: NotRequired[bool] - """Apply the SQLite extension-store PRAGMA profile. Default: False.""" - - pragma_overrides: NotRequired[dict[str, str | int | bool]] - """Apply validated SQLite PRAGMA overrides after the optional profile.""" diff --git a/tests/typing/typing_litestar_config.py b/tests/typing/typing_litestar_config.py new file mode 100644 index 000000000..f8ce473cd --- /dev/null +++ b/tests/typing/typing_litestar_config.py @@ -0,0 +1,24 @@ +"""The public Litestar config accepts plugin options and boolean session setup.""" + +from sqlspec.config import ExtensionConfigs +from sqlspec.extensions.litestar import LitestarConfig + + +def litestar_extension_config() -> ExtensionConfigs: + config: LitestarConfig = { + "session_table": True, + "auto_trace_headers": True, + "commit_mode": "autocommit", + "connection_key": "connection", + "correlation_header": "X-Request-ID", + "correlation_headers": ["X-Correlation-ID"], + "disable_di": False, + "enable_correlation_middleware": True, + "enable_sqlcommenter_middleware": True, + "extra_commit_statuses": {201}, + "extra_rollback_statuses": {409}, + "migrations_path": "migrations", + "pool_key": "pool", + "session_key": "session", + } + return {"litestar": config} diff --git a/tests/unit/extensions/test_litestar/test_config_typing.py b/tests/unit/extensions/test_litestar/test_config_typing.py new file mode 100644 index 000000000..b583748fc --- /dev/null +++ b/tests/unit/extensions/test_litestar/test_config_typing.py @@ -0,0 +1,10 @@ +"""The Litestar extension exposes the canonical configuration type.""" + +from sqlspec.config import LitestarConfig +from sqlspec.extensions.litestar import LitestarConfig as PublicLitestarConfig +from sqlspec.extensions.litestar.config import LitestarConfig as ExtensionLitestarConfig + + +def test_litestar_config_reexports() -> None: + assert PublicLitestarConfig is LitestarConfig + assert ExtensionLitestarConfig is LitestarConfig From 832ae89881c4cb56c2dbd892666469ad6d252dd5 Mon Sep 17 00:00:00 2001 From: Cody Fincher Date: Thu, 10 Sep 2026 19:04:24 +0000 Subject: [PATCH 2/2] refactor: remove superseded exception wrapper --- docs/changelog.rst | 14 +++++++++++ sqlspec/exceptions.py | 29 --------------------- tests/unit/exceptions/test_exceptions.py | 32 ------------------------ 3 files changed, 14 insertions(+), 61 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index a37b4203c..bc8cfea8b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -9,6 +9,20 @@ important operational fixes. Recent Updates ============== +Unreleased +---------- + +**Fixed:** + +* ``sqlspec.extensions.litestar.LitestarConfig`` now exposes the complete plugin + configuration, including ``session_table=True``, through the same type as + ``sqlspec.config.LitestarConfig``. + +**Removed:** + +* Removed the undocumented ``sqlspec.exceptions.wrap_exceptions`` helper, + superseded by the typed per-adapter exception handlers. + v0.62.2 - Litestar config lookup diagnostics --------------------------------------------- diff --git a/sqlspec/exceptions.py b/sqlspec/exceptions.py index 43f047ec3..0d980a3c9 100644 --- a/sqlspec/exceptions.py +++ b/sqlspec/exceptions.py @@ -1,5 +1,3 @@ -from collections.abc import Generator -from contextlib import contextmanager from typing import Any, Final __all__ = ( @@ -465,30 +463,3 @@ def _classify_timeout_or_cancellation(message: str) -> "type[OperationalError] | if any(marker in error_msg for marker in cancellation_markers): return OperationCancelledError return None - - -@contextmanager -def wrap_exceptions( - wrap_exceptions: bool = True, suppress: "type[Exception] | tuple[type[Exception], ...] | None" = None -) -> Generator[None, None, None]: - """Context manager for exception handling with optional suppression. - - Args: - wrap_exceptions: If True, wrap exceptions in RepositoryError. If False, let them pass through. - suppress: Exception type(s) to suppress completely (like contextlib.suppress). - If provided, these exceptions are caught and ignored. - """ - try: - yield - - except Exception as exc: - if suppress is not None and isinstance(exc, suppress): - return - - if isinstance(exc, SQLSpecError): - raise - - if wrap_exceptions is False: - raise - msg = "An error occurred during the operation." - raise RepositoryError(detail=msg) from exc diff --git a/tests/unit/exceptions/test_exceptions.py b/tests/unit/exceptions/test_exceptions.py index 7bc7b8ff5..db769b689 100644 --- a/tests/unit/exceptions/test_exceptions.py +++ b/tests/unit/exceptions/test_exceptions.py @@ -1,5 +1,3 @@ -import pytest - from sqlspec.exceptions import ( CheckViolationError, DatabaseConnectionError, @@ -9,14 +7,12 @@ NotFoundError, NotNullViolationError, OperationalError, - RepositoryError, SQLFileNotFoundError, SQLSpecError, SQLStatementNotFoundError, StackExecutionError, TransactionError, UniqueViolationError, - wrap_exceptions, ) @@ -172,31 +168,3 @@ def test_stack_execution_error_preserves_args() -> None: assert len(exc.args) == 1 assert "operation 2" in exc.args[0] assert exc.args[0] == exc.detail - - -def test_wrap_exceptions_wrap_exceptions_suppresses_single_type() -> None: - """suppress= silently swallows matching exceptions.""" - with wrap_exceptions(suppress=ValueError): - raise ValueError("suppressed") - - -def test_wrap_exceptions_wrap_exceptions_suppresses_tuple_of_types() -> None: - """suppress=(, ...) silently swallows matching exceptions.""" - with wrap_exceptions(suppress=(ValueError, TypeError)): - raise TypeError("suppressed") - - -def test_wrap_exceptions_wrap_exceptions_wraps_unmatched_suppressed_type() -> None: - """Non-matching exceptions are still wrapped.""" - with pytest.raises(RepositoryError): - with wrap_exceptions(suppress=ValueError): - raise RuntimeError("not suppressed") - - -def test_wrap_exceptions_wrap_exceptions_sqlspec_error_passes_through() -> None: - """SQLSpecError is reraised when it is not explicitly suppressed.""" - original = SQLSpecError("already mapped") - with pytest.raises(SQLSpecError) as exc_info: - with wrap_exceptions(): - raise original - assert exc_info.value is original