fix: register session listeners in framework extension configs (#709)#711
Closed
hasansezertasan wants to merge 18 commits intolitestar-org:mainfrom
Closed
fix: register session listeners in framework extension configs (#709)#711hasansezertasan wants to merge 18 commits intolitestar-org:mainfrom
hasansezertasan wants to merge 18 commits intolitestar-org:mainfrom
Conversation
Regression tests for litestar-org#709. Lock the contract that the Litestar SQLAlchemyAsyncConfig subclass must register the base-class listener set (file-object, timestamp, cache) when create_session_maker() is called. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Regression tests for litestar-org#709. Lock the contract that the Litestar SQLAlchemySyncConfig subclass must register the base-class listener set directly on the session_maker. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Regression tests for litestar-org#709. Lock the contract that both Starlette async and sync config subclasses must register the base-class listener set when create_session_maker() is called. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Regression tests for litestar-org#709. Lock the contract that both Sanic async and sync config subclasses must register the base-class listener set when create_session_maker() is called. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Regression tests for litestar-org#709. Lock the contract that both Flask async and sync config subclasses must register the base-class listener set when create_session_maker() is called. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ring (litestar-org#709) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…er wiring (litestar-org#709) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ener wiring (litestar-org#709) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ner wiring (litestar-org#709) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… wiring (litestar-org#709) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…wiring (litestar-org#709) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…wiring (litestar-org#709) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… wiring (litestar-org#709) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Starlette/Sanic/Flask listener tests call create_session_maker on a fresh config. When get_engine() runs for real, the aiosqlite dialect registers spurious event.listen calls that pollute the mock count. Pre-populating engine_instance with a MagicMock makes get_engine() short-circuit so only the listener-registration path contributes to the mock. This unblocks restoring the engine_instance caching pre-step in the extension overrides per the "minimal harm" design directive from litestar-org#709. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Preserves exact observable behavior of the previous override: engine_instance is populated during create_session_maker, not lazily on a later get_engine() call. This honors the "minimal harm" design directive from the litestar-org#709 reviewer. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Preserves exact observable behavior of the previous overrides: engine_instance is populated during create_session_maker, not lazily on a later get_engine() call. Honors the "minimal harm" design directive from the litestar-org#709 reviewer. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Preserves exact observable behavior of the previous overrides: engine_instance is populated during create_session_maker, not lazily on a later get_engine() call. Honors the "minimal harm" design directive from the litestar-org#709 reviewer. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add per-call target assertions (every listener attached to the synthetic sync_maker, not the async session_maker) and event-name set assertion to match the reference pattern in test_config/test_async_config.py and the Litestar async listener test. Catches a regression where listeners are incorrectly attached to the async session_maker instead of the synthetic sync_maker. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
4 tasks
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #709 — framework extension configs (Litestar, Starlette, Sanic, Flask, async and sync each) override
create_session_makerwithout delegating tosuper(), silently skippingAsyncFileObjectListener/SyncFileObjectListener,touch_updated_timestamp, andAsyncCacheListener/SyncCacheListenerregistration. User-visible effect: file uploads viaFileObject/StoredObjectpersist metadata to the database but the actual file content is silently discarded.super().create_session_maker()so the middle-layer listener wiring runs. Framework-specific pre-steps (notably Starlette/Sanic/Flask'sengine_instancecaching) are preserved verbatim — the principle is add listener wiring, preserve every other observable behavior.tests/unit/test_config/test_async_config.py, locking the listener-registration contract per extension so future overrides cannot silently drop it again.Design notes
call_count == 0vs expected6), whereas an integration test would fail as a confusing silent missing-file, which is exactly the failure mode Bug: LitestarSQLAlchemyAsyncConfig.create_session_maker()does not register FileObject session listeners #709 reported.engine_instancepre-step preserved in Starlette/Sanic/Flask? Analysis shows it's technically redundant withget_engine()'s internal memoization, so the overrides could be deleted outright. But "minimal harm" mandates preserving exact call sequences in case downstream users have subclassed or monkey-patched in unexpected ways. The tests pre-populateconfig.engine_instance = MagicMock()to isolate listener-count assertions from the aiosqlite dialect's internalevent.listencalls.Test Plan
tests/unit/suite — no regressions (pre-existing failures intest_repository.pyandtest_utils/test_fixtures.pyconfirmed unrelated by checking out base commit)SQLAlchemyAsyncConfig.create_session_maker()does not register FileObject session listeners #709 now produces"file_exists_on_disk": trueengine_instancepre-step) matches project preferenceDraft status
Drafting for reviewer discussion on:
engine_instancepre-step or delete the non-Litestar overrides outright (simpler, provably safe perget_engine()memoization analysis).🤖 Generated with Claude Code